@camstack/addon-decoder-nodeav 1.2.24 → 1.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/dist/index.js +262 -120
- package/dist/index.mjs +262 -120
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
6
|
-
//#region ../types/dist/event-category-
|
|
6
|
+
//#region ../types/dist/event-category-CIa_iT6b.mjs
|
|
7
7
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
8
8
|
EventCategory["SystemBoot"] = "system.boot";
|
|
9
9
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -19,6 +19,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
19
19
|
*/
|
|
20
20
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
21
21
|
/**
|
|
22
|
+
* The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
|
|
23
|
+
* Emitted only when the material on disk actually changed, so an
|
|
24
|
+
* operator who trusted the old certificate by hand is told rather than
|
|
25
|
+
* discovering it as a browser error. Payload `TlsCertChangedPayload`.
|
|
26
|
+
*
|
|
27
|
+
* Rule: docs/decisions/adr-0227-*.md
|
|
28
|
+
*/
|
|
29
|
+
EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
|
|
30
|
+
/**
|
|
22
31
|
* A newer addon or server-root package version was found by the
|
|
23
32
|
* authoritative registry check. Emitted once when any observed
|
|
24
33
|
* `latestVersion` changes (or a package/node first appears behind);
|
|
@@ -8011,6 +8020,15 @@ var LabelDefinitionSchema = object({
|
|
|
8011
8020
|
description: string().optional(),
|
|
8012
8021
|
icon: string().optional()
|
|
8013
8022
|
});
|
|
8023
|
+
var ClassMapDefinitionSchema = object({
|
|
8024
|
+
mapping: record(string(), _enum([
|
|
8025
|
+
"person",
|
|
8026
|
+
"vehicle",
|
|
8027
|
+
"animal",
|
|
8028
|
+
"package"
|
|
8029
|
+
])),
|
|
8030
|
+
preserveOriginal: boolean()
|
|
8031
|
+
});
|
|
8014
8032
|
var MODEL_FORMATS = [
|
|
8015
8033
|
"onnx",
|
|
8016
8034
|
"coreml",
|
|
@@ -8189,7 +8207,13 @@ var ModelCatalogEntrySchema = object({
|
|
|
8189
8207
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
8190
8208
|
* is a presentation overlay resolved back to an `id`.
|
|
8191
8209
|
*/
|
|
8192
|
-
group: ModelVariantGroupSchema.optional()
|
|
8210
|
+
group: ModelVariantGroupSchema.optional(),
|
|
8211
|
+
/**
|
|
8212
|
+
* Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
|
|
8213
|
+
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
8214
|
+
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
8215
|
+
*/
|
|
8216
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8193
8217
|
});
|
|
8194
8218
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8195
8219
|
format: literal("openvino"),
|
|
@@ -8218,7 +8242,8 @@ var ModelConvertMetadataSchema = object({
|
|
|
8218
8242
|
"ocr",
|
|
8219
8243
|
"segmentation"
|
|
8220
8244
|
]),
|
|
8221
|
-
faceAlignment: boolean().optional()
|
|
8245
|
+
faceAlignment: boolean().optional(),
|
|
8246
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8222
8247
|
});
|
|
8223
8248
|
var ConvertResultSchema = object({
|
|
8224
8249
|
entry: ModelCatalogEntrySchema,
|
|
@@ -17339,6 +17364,33 @@ var NativeCropRefSchema = object({
|
|
|
17339
17364
|
h: number()
|
|
17340
17365
|
})
|
|
17341
17366
|
});
|
|
17367
|
+
object({
|
|
17368
|
+
crop: object({
|
|
17369
|
+
left: number(),
|
|
17370
|
+
top: number(),
|
|
17371
|
+
width: number().positive(),
|
|
17372
|
+
height: number().positive()
|
|
17373
|
+
}).optional(),
|
|
17374
|
+
content: object({
|
|
17375
|
+
width: number().int().positive(),
|
|
17376
|
+
height: number().int().positive()
|
|
17377
|
+
}),
|
|
17378
|
+
fit: _enum(["stretch", "contain"]),
|
|
17379
|
+
format: _enum([
|
|
17380
|
+
"rgb",
|
|
17381
|
+
"gray",
|
|
17382
|
+
"jpeg"
|
|
17383
|
+
])
|
|
17384
|
+
});
|
|
17385
|
+
var FrameRefSchema = object({
|
|
17386
|
+
registryId: string().min(1),
|
|
17387
|
+
id: string().min(1),
|
|
17388
|
+
width: number().int().positive(),
|
|
17389
|
+
height: number().int().positive(),
|
|
17390
|
+
format: _enum(["rgb", "gray"]),
|
|
17391
|
+
timestamp: number(),
|
|
17392
|
+
capturedAt: number().optional()
|
|
17393
|
+
});
|
|
17342
17394
|
var ModelFormatSchema$1 = _enum([
|
|
17343
17395
|
"onnx",
|
|
17344
17396
|
"coreml",
|
|
@@ -17583,6 +17635,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
17583
17635
|
steps: array(PipelineStepInputSchema).min(1),
|
|
17584
17636
|
frame: FrameInputSchema.optional(),
|
|
17585
17637
|
/**
|
|
17638
|
+
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
17639
|
+
* in the same execution-group process; split/cross-node callers use
|
|
17640
|
+
* `frame`/`image` inline compatibility instead.
|
|
17641
|
+
*/
|
|
17642
|
+
frameRef: FrameRefSchema.optional(),
|
|
17643
|
+
/**
|
|
17586
17644
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
17587
17645
|
* the decoded pixels live in. One more member of the one-of
|
|
17588
17646
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -17838,7 +17896,10 @@ var NativeCropResultSchema = object({
|
|
|
17838
17896
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
17839
17897
|
* `keyFrame`) can reject a degraded fallback:
|
|
17840
17898
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
17841
|
-
* quality path).
|
|
17899
|
+
* quality path). A subject-tile serve is also native-resolution and stays
|
|
17900
|
+
* `native` here: the public enum cannot name `tile` without a breaking cap
|
|
17901
|
+
* change. Runner telemetry distinguishes lease vs tile via `source` on the
|
|
17902
|
+
* internal crop result (`nativeHits` vs `tileHits`).
|
|
17842
17903
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
17843
17904
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
17844
17905
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -18329,12 +18390,41 @@ var RunnerLocalLoadSchema = object({
|
|
|
18329
18390
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
18330
18391
|
* working unchanged when they switch to reading from the runner cap.
|
|
18331
18392
|
*/
|
|
18393
|
+
var FrameLazyCountersSchema = object({
|
|
18394
|
+
framesDecoded: number(),
|
|
18395
|
+
framesAdmitted: number(),
|
|
18396
|
+
framesDroppedPixelFree: number(),
|
|
18397
|
+
viewsMaterialized: number(),
|
|
18398
|
+
viewsSkipped: number(),
|
|
18399
|
+
workerToRunnerBytes: number(),
|
|
18400
|
+
runnerToPoolRawBytes: number(),
|
|
18401
|
+
runnerToPoolJpegBytes: number(),
|
|
18402
|
+
onDemandFullFrameRequests: number(),
|
|
18403
|
+
onDemandCropRequests: number(),
|
|
18404
|
+
nativeHits: number(),
|
|
18405
|
+
nativeMisses: number(),
|
|
18406
|
+
tileHits: number(),
|
|
18407
|
+
tileMisses: number(),
|
|
18408
|
+
fallbackHits: number(),
|
|
18409
|
+
fallbackMisses: number(),
|
|
18410
|
+
retainedWritesAvoided: number(),
|
|
18411
|
+
residentRefs: number(),
|
|
18412
|
+
residentBytes: number(),
|
|
18413
|
+
releases: number(),
|
|
18414
|
+
evictions: number(),
|
|
18415
|
+
staleMisses: number()
|
|
18416
|
+
});
|
|
18417
|
+
var FrameLazyMetricsSchema = object({
|
|
18418
|
+
node: FrameLazyCountersSchema,
|
|
18419
|
+
cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
|
|
18420
|
+
});
|
|
18332
18421
|
var RunnerLocalMetricsSchema = object({
|
|
18333
18422
|
nodeId: string(),
|
|
18334
18423
|
activeCameras: number(),
|
|
18335
18424
|
throttledCameras: number(),
|
|
18336
18425
|
avgInferenceTimeMs: number(),
|
|
18337
|
-
queueDepth: number()
|
|
18426
|
+
queueDepth: number(),
|
|
18427
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
18338
18428
|
});
|
|
18339
18429
|
method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
|
|
18340
18430
|
handle: FrameHandleSchema,
|
|
@@ -19634,6 +19724,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
|
|
|
19634
19724
|
location: StorageLocationSchema,
|
|
19635
19725
|
relativePath: string()
|
|
19636
19726
|
}), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
|
|
19727
|
+
/** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
|
|
19728
|
+
var ProfileSettingsSchemaBridge = unknown().nullable();
|
|
19729
|
+
var ProfileSettingsBagSchema = record(string(), unknown());
|
|
19637
19730
|
/**
|
|
19638
19731
|
* A live terminal session hosted by the provider addon. Output and input do
|
|
19639
19732
|
* NOT flow through the capability — they use the addon data plane
|
|
@@ -19663,7 +19756,14 @@ var TerminalSessionInfoSchema = object({
|
|
|
19663
19756
|
var TerminalProfileInfoSchema = object({
|
|
19664
19757
|
profileId: string(),
|
|
19665
19758
|
label: string(),
|
|
19666
|
-
description: string().optional()
|
|
19759
|
+
description: string().optional(),
|
|
19760
|
+
/** Spawn defaults the instance form copies on create. */
|
|
19761
|
+
executable: string().optional(),
|
|
19762
|
+
args: array(string()).readonly().optional(),
|
|
19763
|
+
cwd: string().optional(),
|
|
19764
|
+
environment: array(string()).readonly().optional(),
|
|
19765
|
+
/** ConfigUISchema for instance knobs, or null when the profile has none. */
|
|
19766
|
+
settingsSchema: ProfileSettingsSchemaBridge.optional()
|
|
19667
19767
|
});
|
|
19668
19768
|
/**
|
|
19669
19769
|
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
@@ -19676,7 +19776,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
19676
19776
|
profileId: string(),
|
|
19677
19777
|
profileLabel: string(),
|
|
19678
19778
|
name: string(),
|
|
19679
|
-
enabled: boolean()
|
|
19779
|
+
enabled: boolean(),
|
|
19780
|
+
executable: string(),
|
|
19781
|
+
args: array(string()).readonly(),
|
|
19782
|
+
cwd: string(),
|
|
19783
|
+
environment: array(string()).readonly(),
|
|
19784
|
+
profileSettings: ProfileSettingsBagSchema
|
|
19680
19785
|
});
|
|
19681
19786
|
var TerminalLegacyCameraSchema = object({
|
|
19682
19787
|
stableId: string(),
|
|
@@ -19706,7 +19811,23 @@ var TerminalOutputBatchSchema = object({
|
|
|
19706
19811
|
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19707
19812
|
targetNodeId: string().min(1),
|
|
19708
19813
|
profileId: string().min(1),
|
|
19709
|
-
name: string().trim().min(1).max(160).optional()
|
|
19814
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19815
|
+
executable: string().max(1024).optional(),
|
|
19816
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19817
|
+
cwd: string().max(1024).optional(),
|
|
19818
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
19819
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19820
|
+
}), TerminalInstanceInfoSchema, {
|
|
19821
|
+
kind: "mutation",
|
|
19822
|
+
auth: "admin"
|
|
19823
|
+
}), method(object({
|
|
19824
|
+
instanceId: string().min(1),
|
|
19825
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19826
|
+
executable: string().max(1024).optional(),
|
|
19827
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19828
|
+
cwd: string().max(1024).optional(),
|
|
19829
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
19830
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19710
19831
|
}), TerminalInstanceInfoSchema, {
|
|
19711
19832
|
kind: "mutation",
|
|
19712
19833
|
auth: "admin"
|
|
@@ -19728,7 +19849,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19728
19849
|
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19729
19850
|
profileId: string(),
|
|
19730
19851
|
cols: number().int().positive(),
|
|
19731
|
-
rows: number().int().positive()
|
|
19852
|
+
rows: number().int().positive(),
|
|
19853
|
+
executable: string().max(1024).optional(),
|
|
19854
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19855
|
+
cwd: string().max(1024).optional(),
|
|
19856
|
+
environment: array(string().max(4096)).max(64).optional()
|
|
19732
19857
|
}), TerminalSessionInfoSchema, {
|
|
19733
19858
|
kind: "mutation",
|
|
19734
19859
|
auth: "admin"
|
|
@@ -22510,10 +22635,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
|
|
|
22510
22635
|
*
|
|
22511
22636
|
* • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
|
|
22512
22637
|
* to receive an ordered list of candidate base URLs it should race
|
|
22513
|
-
* on connect — LAN IPv4 first (lowest latency
|
|
22514
|
-
* then public hostname (if a tunnel is
|
|
22515
|
-
* race them with short timeouts and stick with the
|
|
22516
|
-
* session.
|
|
22638
|
+
* on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
|
|
22639
|
+
* when on the same network), then public hostname (if a tunnel is
|
|
22640
|
+
* up). The SDK can race them with short timeouts and stick with the
|
|
22641
|
+
* winner for the session.
|
|
22517
22642
|
*
|
|
22518
22643
|
* Why hub-only: agents are not directly addressable by the operator's
|
|
22519
22644
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
@@ -22668,6 +22793,17 @@ var NotificationEndpointSchema = object({
|
|
|
22668
22793
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
22669
22794
|
resolved: string().nullable()
|
|
22670
22795
|
});
|
|
22796
|
+
/**
|
|
22797
|
+
* The URLs the SDK / viewer should race for API access. `baseUrls` empty =
|
|
22798
|
+
* AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
|
|
22799
|
+
* currently expands to, so the UI can show the effective set either way.
|
|
22800
|
+
*/
|
|
22801
|
+
var ViewerEndpointsSchema = object({
|
|
22802
|
+
/** The operator's explicit race set, or empty for AUTO. */
|
|
22803
|
+
baseUrls: array(string()).readonly(),
|
|
22804
|
+
/** What the ranking currently resolves to (may be empty if nothing is up). */
|
|
22805
|
+
resolved: array(string()).readonly()
|
|
22806
|
+
});
|
|
22671
22807
|
var AllowedAddressesSchema = object({
|
|
22672
22808
|
/**
|
|
22673
22809
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -22676,6 +22812,20 @@ var AllowedAddressesSchema = object({
|
|
|
22676
22812
|
* Network Addresses admin page and persisted by the addon.
|
|
22677
22813
|
*/
|
|
22678
22814
|
addresses: array(string()).readonly() });
|
|
22815
|
+
var TlsStatusSchema = object({
|
|
22816
|
+
mode: _enum([
|
|
22817
|
+
"generated",
|
|
22818
|
+
"uploaded",
|
|
22819
|
+
"disabled"
|
|
22820
|
+
]),
|
|
22821
|
+
leafFingerprintSha256: string().nullable(),
|
|
22822
|
+
caFingerprintSha256: string().nullable(),
|
|
22823
|
+
validTo: string().nullable(),
|
|
22824
|
+
sans: array(string()),
|
|
22825
|
+
caCertPem: string().nullable(),
|
|
22826
|
+
reissueError: string().nullable(),
|
|
22827
|
+
restartRequired: boolean()
|
|
22828
|
+
});
|
|
22679
22829
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
22680
22830
|
/**
|
|
22681
22831
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -22685,17 +22835,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
22685
22835
|
*/
|
|
22686
22836
|
port: number().int().min(1).max(65535).optional(),
|
|
22687
22837
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
22688
|
-
* candidate. Default `
|
|
22838
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
22689
22839
|
includeLoopback: boolean().optional(),
|
|
22690
|
-
/** Skip IPv6 entries.
|
|
22691
|
-
*
|
|
22840
|
+
/** Skip IPv6 entries. Default `false` — the palette includes stable
|
|
22841
|
+
* LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
|
|
22842
|
+
* hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
|
|
22692
22843
|
ipv4Only: boolean().optional(),
|
|
22693
22844
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
22694
22845
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
22695
22846
|
* to avoid mixed-content blocks in the browser. The public
|
|
22696
22847
|
* tunnel always emits `https://` regardless. */
|
|
22697
22848
|
scheme: _enum(["http", "https"]).optional()
|
|
22698
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" })
|
|
22849
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
|
|
22850
|
+
kind: "mutation",
|
|
22851
|
+
auth: "admin"
|
|
22852
|
+
}), method(object({
|
|
22853
|
+
certPem: string().min(1),
|
|
22854
|
+
keyPem: string().min(1),
|
|
22855
|
+
caPem: string().optional()
|
|
22856
|
+
}), TlsStatusSchema, {
|
|
22857
|
+
kind: "mutation",
|
|
22858
|
+
auth: "admin"
|
|
22859
|
+
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
22860
|
+
kind: "mutation",
|
|
22861
|
+
auth: "admin"
|
|
22862
|
+
});
|
|
22699
22863
|
object({
|
|
22700
22864
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
22701
22865
|
* failure to reach the target — operator intervention required. */
|
|
@@ -28458,6 +28622,12 @@ Object.freeze({
|
|
|
28458
28622
|
addonId: null,
|
|
28459
28623
|
access: "create"
|
|
28460
28624
|
},
|
|
28625
|
+
"localNetwork.downloadCa": {
|
|
28626
|
+
capName: "local-network",
|
|
28627
|
+
capScope: "system",
|
|
28628
|
+
addonId: null,
|
|
28629
|
+
access: "view"
|
|
28630
|
+
},
|
|
28461
28631
|
"localNetwork.getAllowedAddresses": {
|
|
28462
28632
|
capName: "local-network",
|
|
28463
28633
|
capScope: "system",
|
|
@@ -28482,18 +28652,42 @@ Object.freeze({
|
|
|
28482
28652
|
addonId: null,
|
|
28483
28653
|
access: "view"
|
|
28484
28654
|
},
|
|
28655
|
+
"localNetwork.getTlsStatus": {
|
|
28656
|
+
capName: "local-network",
|
|
28657
|
+
capScope: "system",
|
|
28658
|
+
addonId: null,
|
|
28659
|
+
access: "view"
|
|
28660
|
+
},
|
|
28661
|
+
"localNetwork.getViewerEndpoints": {
|
|
28662
|
+
capName: "local-network",
|
|
28663
|
+
capScope: "system",
|
|
28664
|
+
addonId: null,
|
|
28665
|
+
access: "view"
|
|
28666
|
+
},
|
|
28485
28667
|
"localNetwork.list": {
|
|
28486
28668
|
capName: "local-network",
|
|
28487
28669
|
capScope: "system",
|
|
28488
28670
|
addonId: null,
|
|
28489
28671
|
access: "view"
|
|
28490
28672
|
},
|
|
28673
|
+
"localNetwork.regenerateCertificate": {
|
|
28674
|
+
capName: "local-network",
|
|
28675
|
+
capScope: "system",
|
|
28676
|
+
addonId: null,
|
|
28677
|
+
access: "create"
|
|
28678
|
+
},
|
|
28491
28679
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
28492
28680
|
capName: "local-network",
|
|
28493
28681
|
capScope: "system",
|
|
28494
28682
|
addonId: null,
|
|
28495
28683
|
access: "delete"
|
|
28496
28684
|
},
|
|
28685
|
+
"localNetwork.revertToGeneratedCertificate": {
|
|
28686
|
+
capName: "local-network",
|
|
28687
|
+
capScope: "system",
|
|
28688
|
+
addonId: null,
|
|
28689
|
+
access: "create"
|
|
28690
|
+
},
|
|
28497
28691
|
"localNetwork.setAllowedAddresses": {
|
|
28498
28692
|
capName: "local-network",
|
|
28499
28693
|
capScope: "system",
|
|
@@ -28506,6 +28700,18 @@ Object.freeze({
|
|
|
28506
28700
|
addonId: null,
|
|
28507
28701
|
access: "create"
|
|
28508
28702
|
},
|
|
28703
|
+
"localNetwork.setViewerEndpoints": {
|
|
28704
|
+
capName: "local-network",
|
|
28705
|
+
capScope: "system",
|
|
28706
|
+
addonId: null,
|
|
28707
|
+
access: "create"
|
|
28708
|
+
},
|
|
28709
|
+
"localNetwork.uploadCertificate": {
|
|
28710
|
+
capName: "local-network",
|
|
28711
|
+
capScope: "system",
|
|
28712
|
+
addonId: null,
|
|
28713
|
+
access: "create"
|
|
28714
|
+
},
|
|
28509
28715
|
"lockControl.lock": {
|
|
28510
28716
|
capName: "lock-control",
|
|
28511
28717
|
capScope: "device",
|
|
@@ -31386,6 +31592,12 @@ Object.freeze({
|
|
|
31386
31592
|
addonId: null,
|
|
31387
31593
|
access: "create"
|
|
31388
31594
|
},
|
|
31595
|
+
"terminalSession.updateInstance": {
|
|
31596
|
+
capName: "terminal-session",
|
|
31597
|
+
capScope: "system",
|
|
31598
|
+
addonId: null,
|
|
31599
|
+
access: "create"
|
|
31600
|
+
},
|
|
31389
31601
|
"terminalSession.writeInput": {
|
|
31390
31602
|
capName: "terminal-session",
|
|
31391
31603
|
capScope: "system",
|
|
@@ -33873,6 +34085,35 @@ Object.freeze(Object.fromEntries([{
|
|
|
33873
34085
|
}]
|
|
33874
34086
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
33875
34087
|
string().min(1);
|
|
34088
|
+
var CLUSTER_STEP_SETTING_FIELDS = [{
|
|
34089
|
+
stepId: "face-embedding",
|
|
34090
|
+
key: "minLandmarkFaceSize",
|
|
34091
|
+
label: "Min face size for recognition (detection px)",
|
|
34092
|
+
description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
|
|
34093
|
+
type: "slider",
|
|
34094
|
+
min: 0,
|
|
34095
|
+
max: 64,
|
|
34096
|
+
step: 2,
|
|
34097
|
+
default: 24
|
|
34098
|
+
}];
|
|
34099
|
+
function clusterStepSettingKey(stepId, fieldKey) {
|
|
34100
|
+
return `clusterStepSetting:${stepId}:${fieldKey}`;
|
|
34101
|
+
}
|
|
34102
|
+
var ClusterSettingNumberSchema = number().finite();
|
|
34103
|
+
function readClusterStepSettings(config) {
|
|
34104
|
+
const out = {};
|
|
34105
|
+
for (const field of CLUSTER_STEP_SETTING_FIELDS) {
|
|
34106
|
+
const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
|
|
34107
|
+
const value = parsed.success ? parsed.data : field.default;
|
|
34108
|
+
const existing = out[field.stepId] ?? {};
|
|
34109
|
+
out[field.stepId] = {
|
|
34110
|
+
...existing,
|
|
34111
|
+
[field.key]: value
|
|
34112
|
+
};
|
|
34113
|
+
}
|
|
34114
|
+
return out;
|
|
34115
|
+
}
|
|
34116
|
+
readClusterStepSettings({});
|
|
33876
34117
|
object({
|
|
33877
34118
|
/**
|
|
33878
34119
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -34200,113 +34441,14 @@ var NotifyingRingBuffer = class {
|
|
|
34200
34441
|
* decoder is an explicit opt-in fallback only. A stale/failed settings read at
|
|
34201
34442
|
* boot therefore resolves to node-av (never leaves the node with no decoder). */
|
|
34202
34443
|
var DEFAULT_DECODER_BACKEND = "nodeav";
|
|
34203
|
-
/** Narrow an unknown settings value to a {@link DecoderBackend}, else `null`. */
|
|
34204
|
-
function parseDecoderBackend(value) {
|
|
34205
|
-
return value === "ffmpeg" || value === "nodeav" ? value : null;
|
|
34206
|
-
}
|
|
34207
|
-
/**
|
|
34208
|
-
* Normalise a raw kernel node id to the bare node id used for scoping.
|
|
34209
|
-
* `localNodeId` can carry a `<node>/<addon>` suffix; the decoder selection is
|
|
34210
|
-
* per-NODE, so strip the addon segment. Falls back to `hub`.
|
|
34211
|
-
*/
|
|
34212
|
-
function normalizeDecoderNodeId(rawNodeId) {
|
|
34213
|
-
const raw = rawNodeId ?? "hub";
|
|
34214
|
-
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
34215
|
-
}
|
|
34216
34444
|
//#endregion
|
|
34217
34445
|
//#region src/shared/decoder-backend.ts
|
|
34218
|
-
/** The NEUTRAL addon (pipeline-orchestrator, hub-resident) whose global
|
|
34219
|
-
* settings OWN the per-node `backend` selector. Neither decoder addon owns
|
|
34220
|
-
* it, so decoder-nodeav / decoder-ffmpeg stay fully independent. */
|
|
34221
|
-
var DECODER_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
34222
|
-
function isHydratedField(entry) {
|
|
34223
|
-
return typeof entry === "object" && entry !== null && "key" in entry;
|
|
34224
|
-
}
|
|
34225
|
-
/**
|
|
34226
|
-
* Pure selection from an already-read hydrated settings payload: extract the
|
|
34227
|
-
* owner's `backend` field value (which the owner projected per-node from its
|
|
34228
|
-
* scoped store key) and narrow it. A missing/invalid field or a null payload
|
|
34229
|
-
* resolves to {@link DEFAULT_DECODER_BACKEND} — never a bare store key.
|
|
34230
|
-
*/
|
|
34231
|
-
function pickDecoderBackendFromSettings(view) {
|
|
34232
|
-
if (view === null) return DEFAULT_DECODER_BACKEND;
|
|
34233
|
-
for (const section of view.sections) for (const entry of section.fields) {
|
|
34234
|
-
if (!isHydratedField(entry) || entry.key !== "backend") continue;
|
|
34235
|
-
return parseDecoderBackend(entry.value) ?? "nodeav";
|
|
34236
|
-
}
|
|
34237
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34238
|
-
}
|
|
34239
|
-
/** Missing optional owner fingerprints: ffmpeg may be uninstalled. */
|
|
34240
|
-
function isMissingOwnerSettingsError(message) {
|
|
34241
|
-
return /not routable/i.test(message) || /provider not available/i.test(message);
|
|
34242
|
-
}
|
|
34243
|
-
/** Transient transport/settings-store fingerprints worth retrying on. */
|
|
34244
|
-
function isTransientSettingsError(message) {
|
|
34245
|
-
return /not loaded/i.test(message) || /transport-failed/i.test(message) || /not connected/i.test(message) || /SqliteSettingsBackend not initialized/i.test(message);
|
|
34246
|
-
}
|
|
34247
34446
|
/**
|
|
34248
|
-
* Resolve the decoder backend
|
|
34249
|
-
*
|
|
34250
|
-
*
|
|
34251
|
-
* The read routes to the owner addon's child runner; during a simultaneous
|
|
34252
|
-
* (re)start the owner may not be up yet → a transient `transport-failed (addon
|
|
34253
|
-
* not loaded)`. Immediately defaulting here would ignore an explicit `ffmpeg`
|
|
34254
|
-
* selection (the node would silently run the node-av default instead). So retry
|
|
34255
|
-
* on the transient fingerprints with a bounded budget (mirrors
|
|
34256
|
-
* `BaseAddon.readAddonStoreWithRetry`) until the owner answers; only a
|
|
34257
|
-
* persistent failure falls back to {@link DEFAULT_DECODER_BACKEND}.
|
|
34258
|
-
*
|
|
34259
|
-
* The OWNER addon must NOT call this (it would self-route + deadlock) — it uses
|
|
34260
|
-
* {@link resolveOwnDecoderBackend} against its own store instead.
|
|
34447
|
+
* Resolve the decoder backend this addon should run. Owner settings are
|
|
34448
|
+
* ignored: persisted `backend@<nodeId>` rows stay in the store and are not
|
|
34449
|
+
* consulted. The runtime default is always {@link DEFAULT_DECODER_BACKEND}.
|
|
34261
34450
|
*/
|
|
34262
|
-
async function resolveDecoderBackend(
|
|
34263
|
-
if (!api) {
|
|
34264
|
-
logger.warn("decoder-backend: no api surface — using default backend", { meta: { default: DEFAULT_DECODER_BACKEND } });
|
|
34265
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34266
|
-
}
|
|
34267
|
-
const normalized = normalizeDecoderNodeId(nodeId);
|
|
34268
|
-
const delaysMs = [
|
|
34269
|
-
150,
|
|
34270
|
-
350,
|
|
34271
|
-
600,
|
|
34272
|
-
900,
|
|
34273
|
-
1200
|
|
34274
|
-
];
|
|
34275
|
-
let lastErr;
|
|
34276
|
-
for (let attempt = 0; attempt <= delaysMs.length; attempt++) {
|
|
34277
|
-
try {
|
|
34278
|
-
const view = await api.addonSettings.getGlobalSettings.query({
|
|
34279
|
-
addonId: DECODER_OWNER_ADDON_ID,
|
|
34280
|
-
nodeId: normalized
|
|
34281
|
-
});
|
|
34282
|
-
if (view !== null) return pickDecoderBackendFromSettings(view);
|
|
34283
|
-
lastErr = /* @__PURE__ */ new Error("owner settings unavailable (null)");
|
|
34284
|
-
} catch (err) {
|
|
34285
|
-
lastErr = err;
|
|
34286
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
34287
|
-
if (isTransientSettingsError(msg)) {} else if (isMissingOwnerSettingsError(msg)) {
|
|
34288
|
-
logger.warn("decoder-backend: optional owner unavailable — using default backend", { meta: {
|
|
34289
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34290
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34291
|
-
error: msg
|
|
34292
|
-
} });
|
|
34293
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34294
|
-
} else {
|
|
34295
|
-
logger.warn("decoder-backend: settings read failed — using default backend", { meta: {
|
|
34296
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34297
|
-
error: msg
|
|
34298
|
-
} });
|
|
34299
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34300
|
-
}
|
|
34301
|
-
}
|
|
34302
|
-
if (attempt === delaysMs.length) break;
|
|
34303
|
-
await new Promise((resolve) => setTimeout(resolve, delaysMs[attempt]));
|
|
34304
|
-
}
|
|
34305
|
-
logger.warn("decoder-backend: owner settings unavailable after retries — using default backend", { meta: {
|
|
34306
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34307
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34308
|
-
error: lastErr instanceof Error ? lastErr.message : String(lastErr)
|
|
34309
|
-
} });
|
|
34451
|
+
async function resolveDecoderBackend(_api, _nodeId, _logger) {
|
|
34310
34452
|
return DEFAULT_DECODER_BACKEND;
|
|
34311
34453
|
}
|
|
34312
34454
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-CIa_iT6b.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -15,6 +15,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
15
15
|
*/
|
|
16
16
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
17
17
|
/**
|
|
18
|
+
* The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
|
|
19
|
+
* Emitted only when the material on disk actually changed, so an
|
|
20
|
+
* operator who trusted the old certificate by hand is told rather than
|
|
21
|
+
* discovering it as a browser error. Payload `TlsCertChangedPayload`.
|
|
22
|
+
*
|
|
23
|
+
* Rule: docs/decisions/adr-0227-*.md
|
|
24
|
+
*/
|
|
25
|
+
EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
|
|
26
|
+
/**
|
|
18
27
|
* A newer addon or server-root package version was found by the
|
|
19
28
|
* authoritative registry check. Emitted once when any observed
|
|
20
29
|
* `latestVersion` changes (or a package/node first appears behind);
|
|
@@ -8007,6 +8016,15 @@ var LabelDefinitionSchema = object({
|
|
|
8007
8016
|
description: string().optional(),
|
|
8008
8017
|
icon: string().optional()
|
|
8009
8018
|
});
|
|
8019
|
+
var ClassMapDefinitionSchema = object({
|
|
8020
|
+
mapping: record(string(), _enum([
|
|
8021
|
+
"person",
|
|
8022
|
+
"vehicle",
|
|
8023
|
+
"animal",
|
|
8024
|
+
"package"
|
|
8025
|
+
])),
|
|
8026
|
+
preserveOriginal: boolean()
|
|
8027
|
+
});
|
|
8010
8028
|
var MODEL_FORMATS = [
|
|
8011
8029
|
"onnx",
|
|
8012
8030
|
"coreml",
|
|
@@ -8185,7 +8203,13 @@ var ModelCatalogEntrySchema = object({
|
|
|
8185
8203
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
8186
8204
|
* is a presentation overlay resolved back to an `id`.
|
|
8187
8205
|
*/
|
|
8188
|
-
group: ModelVariantGroupSchema.optional()
|
|
8206
|
+
group: ModelVariantGroupSchema.optional(),
|
|
8207
|
+
/**
|
|
8208
|
+
* Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
|
|
8209
|
+
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
8210
|
+
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
8211
|
+
*/
|
|
8212
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8189
8213
|
});
|
|
8190
8214
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8191
8215
|
format: literal("openvino"),
|
|
@@ -8214,7 +8238,8 @@ var ModelConvertMetadataSchema = object({
|
|
|
8214
8238
|
"ocr",
|
|
8215
8239
|
"segmentation"
|
|
8216
8240
|
]),
|
|
8217
|
-
faceAlignment: boolean().optional()
|
|
8241
|
+
faceAlignment: boolean().optional(),
|
|
8242
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8218
8243
|
});
|
|
8219
8244
|
var ConvertResultSchema = object({
|
|
8220
8245
|
entry: ModelCatalogEntrySchema,
|
|
@@ -17335,6 +17360,33 @@ var NativeCropRefSchema = object({
|
|
|
17335
17360
|
h: number()
|
|
17336
17361
|
})
|
|
17337
17362
|
});
|
|
17363
|
+
object({
|
|
17364
|
+
crop: object({
|
|
17365
|
+
left: number(),
|
|
17366
|
+
top: number(),
|
|
17367
|
+
width: number().positive(),
|
|
17368
|
+
height: number().positive()
|
|
17369
|
+
}).optional(),
|
|
17370
|
+
content: object({
|
|
17371
|
+
width: number().int().positive(),
|
|
17372
|
+
height: number().int().positive()
|
|
17373
|
+
}),
|
|
17374
|
+
fit: _enum(["stretch", "contain"]),
|
|
17375
|
+
format: _enum([
|
|
17376
|
+
"rgb",
|
|
17377
|
+
"gray",
|
|
17378
|
+
"jpeg"
|
|
17379
|
+
])
|
|
17380
|
+
});
|
|
17381
|
+
var FrameRefSchema = object({
|
|
17382
|
+
registryId: string().min(1),
|
|
17383
|
+
id: string().min(1),
|
|
17384
|
+
width: number().int().positive(),
|
|
17385
|
+
height: number().int().positive(),
|
|
17386
|
+
format: _enum(["rgb", "gray"]),
|
|
17387
|
+
timestamp: number(),
|
|
17388
|
+
capturedAt: number().optional()
|
|
17389
|
+
});
|
|
17338
17390
|
var ModelFormatSchema$1 = _enum([
|
|
17339
17391
|
"onnx",
|
|
17340
17392
|
"coreml",
|
|
@@ -17579,6 +17631,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
17579
17631
|
steps: array(PipelineStepInputSchema).min(1),
|
|
17580
17632
|
frame: FrameInputSchema.optional(),
|
|
17581
17633
|
/**
|
|
17634
|
+
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
17635
|
+
* in the same execution-group process; split/cross-node callers use
|
|
17636
|
+
* `frame`/`image` inline compatibility instead.
|
|
17637
|
+
*/
|
|
17638
|
+
frameRef: FrameRefSchema.optional(),
|
|
17639
|
+
/**
|
|
17582
17640
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
17583
17641
|
* the decoded pixels live in. One more member of the one-of
|
|
17584
17642
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -17834,7 +17892,10 @@ var NativeCropResultSchema = object({
|
|
|
17834
17892
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
17835
17893
|
* `keyFrame`) can reject a degraded fallback:
|
|
17836
17894
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
17837
|
-
* quality path).
|
|
17895
|
+
* quality path). A subject-tile serve is also native-resolution and stays
|
|
17896
|
+
* `native` here: the public enum cannot name `tile` without a breaking cap
|
|
17897
|
+
* change. Runner telemetry distinguishes lease vs tile via `source` on the
|
|
17898
|
+
* internal crop result (`nativeHits` vs `tileHits`).
|
|
17838
17899
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
17839
17900
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
17840
17901
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -18325,12 +18386,41 @@ var RunnerLocalLoadSchema = object({
|
|
|
18325
18386
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
18326
18387
|
* working unchanged when they switch to reading from the runner cap.
|
|
18327
18388
|
*/
|
|
18389
|
+
var FrameLazyCountersSchema = object({
|
|
18390
|
+
framesDecoded: number(),
|
|
18391
|
+
framesAdmitted: number(),
|
|
18392
|
+
framesDroppedPixelFree: number(),
|
|
18393
|
+
viewsMaterialized: number(),
|
|
18394
|
+
viewsSkipped: number(),
|
|
18395
|
+
workerToRunnerBytes: number(),
|
|
18396
|
+
runnerToPoolRawBytes: number(),
|
|
18397
|
+
runnerToPoolJpegBytes: number(),
|
|
18398
|
+
onDemandFullFrameRequests: number(),
|
|
18399
|
+
onDemandCropRequests: number(),
|
|
18400
|
+
nativeHits: number(),
|
|
18401
|
+
nativeMisses: number(),
|
|
18402
|
+
tileHits: number(),
|
|
18403
|
+
tileMisses: number(),
|
|
18404
|
+
fallbackHits: number(),
|
|
18405
|
+
fallbackMisses: number(),
|
|
18406
|
+
retainedWritesAvoided: number(),
|
|
18407
|
+
residentRefs: number(),
|
|
18408
|
+
residentBytes: number(),
|
|
18409
|
+
releases: number(),
|
|
18410
|
+
evictions: number(),
|
|
18411
|
+
staleMisses: number()
|
|
18412
|
+
});
|
|
18413
|
+
var FrameLazyMetricsSchema = object({
|
|
18414
|
+
node: FrameLazyCountersSchema,
|
|
18415
|
+
cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
|
|
18416
|
+
});
|
|
18328
18417
|
var RunnerLocalMetricsSchema = object({
|
|
18329
18418
|
nodeId: string(),
|
|
18330
18419
|
activeCameras: number(),
|
|
18331
18420
|
throttledCameras: number(),
|
|
18332
18421
|
avgInferenceTimeMs: number(),
|
|
18333
|
-
queueDepth: number()
|
|
18422
|
+
queueDepth: number(),
|
|
18423
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
18334
18424
|
});
|
|
18335
18425
|
method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
|
|
18336
18426
|
handle: FrameHandleSchema,
|
|
@@ -19630,6 +19720,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
|
|
|
19630
19720
|
location: StorageLocationSchema,
|
|
19631
19721
|
relativePath: string()
|
|
19632
19722
|
}), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
|
|
19723
|
+
/** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
|
|
19724
|
+
var ProfileSettingsSchemaBridge = unknown().nullable();
|
|
19725
|
+
var ProfileSettingsBagSchema = record(string(), unknown());
|
|
19633
19726
|
/**
|
|
19634
19727
|
* A live terminal session hosted by the provider addon. Output and input do
|
|
19635
19728
|
* NOT flow through the capability — they use the addon data plane
|
|
@@ -19659,7 +19752,14 @@ var TerminalSessionInfoSchema = object({
|
|
|
19659
19752
|
var TerminalProfileInfoSchema = object({
|
|
19660
19753
|
profileId: string(),
|
|
19661
19754
|
label: string(),
|
|
19662
|
-
description: string().optional()
|
|
19755
|
+
description: string().optional(),
|
|
19756
|
+
/** Spawn defaults the instance form copies on create. */
|
|
19757
|
+
executable: string().optional(),
|
|
19758
|
+
args: array(string()).readonly().optional(),
|
|
19759
|
+
cwd: string().optional(),
|
|
19760
|
+
environment: array(string()).readonly().optional(),
|
|
19761
|
+
/** ConfigUISchema for instance knobs, or null when the profile has none. */
|
|
19762
|
+
settingsSchema: ProfileSettingsSchemaBridge.optional()
|
|
19663
19763
|
});
|
|
19664
19764
|
/**
|
|
19665
19765
|
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
@@ -19672,7 +19772,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
19672
19772
|
profileId: string(),
|
|
19673
19773
|
profileLabel: string(),
|
|
19674
19774
|
name: string(),
|
|
19675
|
-
enabled: boolean()
|
|
19775
|
+
enabled: boolean(),
|
|
19776
|
+
executable: string(),
|
|
19777
|
+
args: array(string()).readonly(),
|
|
19778
|
+
cwd: string(),
|
|
19779
|
+
environment: array(string()).readonly(),
|
|
19780
|
+
profileSettings: ProfileSettingsBagSchema
|
|
19676
19781
|
});
|
|
19677
19782
|
var TerminalLegacyCameraSchema = object({
|
|
19678
19783
|
stableId: string(),
|
|
@@ -19702,7 +19807,23 @@ var TerminalOutputBatchSchema = object({
|
|
|
19702
19807
|
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19703
19808
|
targetNodeId: string().min(1),
|
|
19704
19809
|
profileId: string().min(1),
|
|
19705
|
-
name: string().trim().min(1).max(160).optional()
|
|
19810
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19811
|
+
executable: string().max(1024).optional(),
|
|
19812
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19813
|
+
cwd: string().max(1024).optional(),
|
|
19814
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
19815
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19816
|
+
}), TerminalInstanceInfoSchema, {
|
|
19817
|
+
kind: "mutation",
|
|
19818
|
+
auth: "admin"
|
|
19819
|
+
}), method(object({
|
|
19820
|
+
instanceId: string().min(1),
|
|
19821
|
+
name: string().trim().min(1).max(160).optional(),
|
|
19822
|
+
executable: string().max(1024).optional(),
|
|
19823
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19824
|
+
cwd: string().max(1024).optional(),
|
|
19825
|
+
environment: array(string().max(4096)).max(64).optional(),
|
|
19826
|
+
profileSettings: ProfileSettingsBagSchema.optional()
|
|
19706
19827
|
}), TerminalInstanceInfoSchema, {
|
|
19707
19828
|
kind: "mutation",
|
|
19708
19829
|
auth: "admin"
|
|
@@ -19724,7 +19845,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19724
19845
|
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19725
19846
|
profileId: string(),
|
|
19726
19847
|
cols: number().int().positive(),
|
|
19727
|
-
rows: number().int().positive()
|
|
19848
|
+
rows: number().int().positive(),
|
|
19849
|
+
executable: string().max(1024).optional(),
|
|
19850
|
+
args: array(string().max(2048)).max(64).optional(),
|
|
19851
|
+
cwd: string().max(1024).optional(),
|
|
19852
|
+
environment: array(string().max(4096)).max(64).optional()
|
|
19728
19853
|
}), TerminalSessionInfoSchema, {
|
|
19729
19854
|
kind: "mutation",
|
|
19730
19855
|
auth: "admin"
|
|
@@ -22506,10 +22631,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
|
|
|
22506
22631
|
*
|
|
22507
22632
|
* • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
|
|
22508
22633
|
* to receive an ordered list of candidate base URLs it should race
|
|
22509
|
-
* on connect — LAN IPv4 first (lowest latency
|
|
22510
|
-
* then public hostname (if a tunnel is
|
|
22511
|
-
* race them with short timeouts and stick with the
|
|
22512
|
-
* session.
|
|
22634
|
+
* on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
|
|
22635
|
+
* when on the same network), then public hostname (if a tunnel is
|
|
22636
|
+
* up). The SDK can race them with short timeouts and stick with the
|
|
22637
|
+
* winner for the session.
|
|
22513
22638
|
*
|
|
22514
22639
|
* Why hub-only: agents are not directly addressable by the operator's
|
|
22515
22640
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
@@ -22664,6 +22789,17 @@ var NotificationEndpointSchema = object({
|
|
|
22664
22789
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
22665
22790
|
resolved: string().nullable()
|
|
22666
22791
|
});
|
|
22792
|
+
/**
|
|
22793
|
+
* The URLs the SDK / viewer should race for API access. `baseUrls` empty =
|
|
22794
|
+
* AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
|
|
22795
|
+
* currently expands to, so the UI can show the effective set either way.
|
|
22796
|
+
*/
|
|
22797
|
+
var ViewerEndpointsSchema = object({
|
|
22798
|
+
/** The operator's explicit race set, or empty for AUTO. */
|
|
22799
|
+
baseUrls: array(string()).readonly(),
|
|
22800
|
+
/** What the ranking currently resolves to (may be empty if nothing is up). */
|
|
22801
|
+
resolved: array(string()).readonly()
|
|
22802
|
+
});
|
|
22667
22803
|
var AllowedAddressesSchema = object({
|
|
22668
22804
|
/**
|
|
22669
22805
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -22672,6 +22808,20 @@ var AllowedAddressesSchema = object({
|
|
|
22672
22808
|
* Network Addresses admin page and persisted by the addon.
|
|
22673
22809
|
*/
|
|
22674
22810
|
addresses: array(string()).readonly() });
|
|
22811
|
+
var TlsStatusSchema = object({
|
|
22812
|
+
mode: _enum([
|
|
22813
|
+
"generated",
|
|
22814
|
+
"uploaded",
|
|
22815
|
+
"disabled"
|
|
22816
|
+
]),
|
|
22817
|
+
leafFingerprintSha256: string().nullable(),
|
|
22818
|
+
caFingerprintSha256: string().nullable(),
|
|
22819
|
+
validTo: string().nullable(),
|
|
22820
|
+
sans: array(string()),
|
|
22821
|
+
caCertPem: string().nullable(),
|
|
22822
|
+
reissueError: string().nullable(),
|
|
22823
|
+
restartRequired: boolean()
|
|
22824
|
+
});
|
|
22675
22825
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
22676
22826
|
/**
|
|
22677
22827
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -22681,17 +22831,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
22681
22831
|
*/
|
|
22682
22832
|
port: number().int().min(1).max(65535).optional(),
|
|
22683
22833
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
22684
|
-
* candidate. Default `
|
|
22834
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
22685
22835
|
includeLoopback: boolean().optional(),
|
|
22686
|
-
/** Skip IPv6 entries.
|
|
22687
|
-
*
|
|
22836
|
+
/** Skip IPv6 entries. Default `false` — the palette includes stable
|
|
22837
|
+
* LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
|
|
22838
|
+
* hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
|
|
22688
22839
|
ipv4Only: boolean().optional(),
|
|
22689
22840
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
22690
22841
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
22691
22842
|
* to avoid mixed-content blocks in the browser. The public
|
|
22692
22843
|
* tunnel always emits `https://` regardless. */
|
|
22693
22844
|
scheme: _enum(["http", "https"]).optional()
|
|
22694
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" })
|
|
22845
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
|
|
22846
|
+
kind: "mutation",
|
|
22847
|
+
auth: "admin"
|
|
22848
|
+
}), method(object({
|
|
22849
|
+
certPem: string().min(1),
|
|
22850
|
+
keyPem: string().min(1),
|
|
22851
|
+
caPem: string().optional()
|
|
22852
|
+
}), TlsStatusSchema, {
|
|
22853
|
+
kind: "mutation",
|
|
22854
|
+
auth: "admin"
|
|
22855
|
+
}), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
|
|
22856
|
+
kind: "mutation",
|
|
22857
|
+
auth: "admin"
|
|
22858
|
+
});
|
|
22695
22859
|
object({
|
|
22696
22860
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
22697
22861
|
* failure to reach the target — operator intervention required. */
|
|
@@ -28454,6 +28618,12 @@ Object.freeze({
|
|
|
28454
28618
|
addonId: null,
|
|
28455
28619
|
access: "create"
|
|
28456
28620
|
},
|
|
28621
|
+
"localNetwork.downloadCa": {
|
|
28622
|
+
capName: "local-network",
|
|
28623
|
+
capScope: "system",
|
|
28624
|
+
addonId: null,
|
|
28625
|
+
access: "view"
|
|
28626
|
+
},
|
|
28457
28627
|
"localNetwork.getAllowedAddresses": {
|
|
28458
28628
|
capName: "local-network",
|
|
28459
28629
|
capScope: "system",
|
|
@@ -28478,18 +28648,42 @@ Object.freeze({
|
|
|
28478
28648
|
addonId: null,
|
|
28479
28649
|
access: "view"
|
|
28480
28650
|
},
|
|
28651
|
+
"localNetwork.getTlsStatus": {
|
|
28652
|
+
capName: "local-network",
|
|
28653
|
+
capScope: "system",
|
|
28654
|
+
addonId: null,
|
|
28655
|
+
access: "view"
|
|
28656
|
+
},
|
|
28657
|
+
"localNetwork.getViewerEndpoints": {
|
|
28658
|
+
capName: "local-network",
|
|
28659
|
+
capScope: "system",
|
|
28660
|
+
addonId: null,
|
|
28661
|
+
access: "view"
|
|
28662
|
+
},
|
|
28481
28663
|
"localNetwork.list": {
|
|
28482
28664
|
capName: "local-network",
|
|
28483
28665
|
capScope: "system",
|
|
28484
28666
|
addonId: null,
|
|
28485
28667
|
access: "view"
|
|
28486
28668
|
},
|
|
28669
|
+
"localNetwork.regenerateCertificate": {
|
|
28670
|
+
capName: "local-network",
|
|
28671
|
+
capScope: "system",
|
|
28672
|
+
addonId: null,
|
|
28673
|
+
access: "create"
|
|
28674
|
+
},
|
|
28487
28675
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
28488
28676
|
capName: "local-network",
|
|
28489
28677
|
capScope: "system",
|
|
28490
28678
|
addonId: null,
|
|
28491
28679
|
access: "delete"
|
|
28492
28680
|
},
|
|
28681
|
+
"localNetwork.revertToGeneratedCertificate": {
|
|
28682
|
+
capName: "local-network",
|
|
28683
|
+
capScope: "system",
|
|
28684
|
+
addonId: null,
|
|
28685
|
+
access: "create"
|
|
28686
|
+
},
|
|
28493
28687
|
"localNetwork.setAllowedAddresses": {
|
|
28494
28688
|
capName: "local-network",
|
|
28495
28689
|
capScope: "system",
|
|
@@ -28502,6 +28696,18 @@ Object.freeze({
|
|
|
28502
28696
|
addonId: null,
|
|
28503
28697
|
access: "create"
|
|
28504
28698
|
},
|
|
28699
|
+
"localNetwork.setViewerEndpoints": {
|
|
28700
|
+
capName: "local-network",
|
|
28701
|
+
capScope: "system",
|
|
28702
|
+
addonId: null,
|
|
28703
|
+
access: "create"
|
|
28704
|
+
},
|
|
28705
|
+
"localNetwork.uploadCertificate": {
|
|
28706
|
+
capName: "local-network",
|
|
28707
|
+
capScope: "system",
|
|
28708
|
+
addonId: null,
|
|
28709
|
+
access: "create"
|
|
28710
|
+
},
|
|
28505
28711
|
"lockControl.lock": {
|
|
28506
28712
|
capName: "lock-control",
|
|
28507
28713
|
capScope: "device",
|
|
@@ -31382,6 +31588,12 @@ Object.freeze({
|
|
|
31382
31588
|
addonId: null,
|
|
31383
31589
|
access: "create"
|
|
31384
31590
|
},
|
|
31591
|
+
"terminalSession.updateInstance": {
|
|
31592
|
+
capName: "terminal-session",
|
|
31593
|
+
capScope: "system",
|
|
31594
|
+
addonId: null,
|
|
31595
|
+
access: "create"
|
|
31596
|
+
},
|
|
31385
31597
|
"terminalSession.writeInput": {
|
|
31386
31598
|
capName: "terminal-session",
|
|
31387
31599
|
capScope: "system",
|
|
@@ -33869,6 +34081,35 @@ Object.freeze(Object.fromEntries([{
|
|
|
33869
34081
|
}]
|
|
33870
34082
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
33871
34083
|
string().min(1);
|
|
34084
|
+
var CLUSTER_STEP_SETTING_FIELDS = [{
|
|
34085
|
+
stepId: "face-embedding",
|
|
34086
|
+
key: "minLandmarkFaceSize",
|
|
34087
|
+
label: "Min face size for recognition (detection px)",
|
|
34088
|
+
description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
|
|
34089
|
+
type: "slider",
|
|
34090
|
+
min: 0,
|
|
34091
|
+
max: 64,
|
|
34092
|
+
step: 2,
|
|
34093
|
+
default: 24
|
|
34094
|
+
}];
|
|
34095
|
+
function clusterStepSettingKey(stepId, fieldKey) {
|
|
34096
|
+
return `clusterStepSetting:${stepId}:${fieldKey}`;
|
|
34097
|
+
}
|
|
34098
|
+
var ClusterSettingNumberSchema = number().finite();
|
|
34099
|
+
function readClusterStepSettings(config) {
|
|
34100
|
+
const out = {};
|
|
34101
|
+
for (const field of CLUSTER_STEP_SETTING_FIELDS) {
|
|
34102
|
+
const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
|
|
34103
|
+
const value = parsed.success ? parsed.data : field.default;
|
|
34104
|
+
const existing = out[field.stepId] ?? {};
|
|
34105
|
+
out[field.stepId] = {
|
|
34106
|
+
...existing,
|
|
34107
|
+
[field.key]: value
|
|
34108
|
+
};
|
|
34109
|
+
}
|
|
34110
|
+
return out;
|
|
34111
|
+
}
|
|
34112
|
+
readClusterStepSettings({});
|
|
33872
34113
|
object({
|
|
33873
34114
|
/**
|
|
33874
34115
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -34196,113 +34437,14 @@ var NotifyingRingBuffer = class {
|
|
|
34196
34437
|
* decoder is an explicit opt-in fallback only. A stale/failed settings read at
|
|
34197
34438
|
* boot therefore resolves to node-av (never leaves the node with no decoder). */
|
|
34198
34439
|
var DEFAULT_DECODER_BACKEND = "nodeav";
|
|
34199
|
-
/** Narrow an unknown settings value to a {@link DecoderBackend}, else `null`. */
|
|
34200
|
-
function parseDecoderBackend(value) {
|
|
34201
|
-
return value === "ffmpeg" || value === "nodeav" ? value : null;
|
|
34202
|
-
}
|
|
34203
|
-
/**
|
|
34204
|
-
* Normalise a raw kernel node id to the bare node id used for scoping.
|
|
34205
|
-
* `localNodeId` can carry a `<node>/<addon>` suffix; the decoder selection is
|
|
34206
|
-
* per-NODE, so strip the addon segment. Falls back to `hub`.
|
|
34207
|
-
*/
|
|
34208
|
-
function normalizeDecoderNodeId(rawNodeId) {
|
|
34209
|
-
const raw = rawNodeId ?? "hub";
|
|
34210
|
-
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
34211
|
-
}
|
|
34212
34440
|
//#endregion
|
|
34213
34441
|
//#region src/shared/decoder-backend.ts
|
|
34214
|
-
/** The NEUTRAL addon (pipeline-orchestrator, hub-resident) whose global
|
|
34215
|
-
* settings OWN the per-node `backend` selector. Neither decoder addon owns
|
|
34216
|
-
* it, so decoder-nodeav / decoder-ffmpeg stay fully independent. */
|
|
34217
|
-
var DECODER_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
34218
|
-
function isHydratedField(entry) {
|
|
34219
|
-
return typeof entry === "object" && entry !== null && "key" in entry;
|
|
34220
|
-
}
|
|
34221
|
-
/**
|
|
34222
|
-
* Pure selection from an already-read hydrated settings payload: extract the
|
|
34223
|
-
* owner's `backend` field value (which the owner projected per-node from its
|
|
34224
|
-
* scoped store key) and narrow it. A missing/invalid field or a null payload
|
|
34225
|
-
* resolves to {@link DEFAULT_DECODER_BACKEND} — never a bare store key.
|
|
34226
|
-
*/
|
|
34227
|
-
function pickDecoderBackendFromSettings(view) {
|
|
34228
|
-
if (view === null) return DEFAULT_DECODER_BACKEND;
|
|
34229
|
-
for (const section of view.sections) for (const entry of section.fields) {
|
|
34230
|
-
if (!isHydratedField(entry) || entry.key !== "backend") continue;
|
|
34231
|
-
return parseDecoderBackend(entry.value) ?? "nodeav";
|
|
34232
|
-
}
|
|
34233
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34234
|
-
}
|
|
34235
|
-
/** Missing optional owner fingerprints: ffmpeg may be uninstalled. */
|
|
34236
|
-
function isMissingOwnerSettingsError(message) {
|
|
34237
|
-
return /not routable/i.test(message) || /provider not available/i.test(message);
|
|
34238
|
-
}
|
|
34239
|
-
/** Transient transport/settings-store fingerprints worth retrying on. */
|
|
34240
|
-
function isTransientSettingsError(message) {
|
|
34241
|
-
return /not loaded/i.test(message) || /transport-failed/i.test(message) || /not connected/i.test(message) || /SqliteSettingsBackend not initialized/i.test(message);
|
|
34242
|
-
}
|
|
34243
34442
|
/**
|
|
34244
|
-
* Resolve the decoder backend
|
|
34245
|
-
*
|
|
34246
|
-
*
|
|
34247
|
-
* The read routes to the owner addon's child runner; during a simultaneous
|
|
34248
|
-
* (re)start the owner may not be up yet → a transient `transport-failed (addon
|
|
34249
|
-
* not loaded)`. Immediately defaulting here would ignore an explicit `ffmpeg`
|
|
34250
|
-
* selection (the node would silently run the node-av default instead). So retry
|
|
34251
|
-
* on the transient fingerprints with a bounded budget (mirrors
|
|
34252
|
-
* `BaseAddon.readAddonStoreWithRetry`) until the owner answers; only a
|
|
34253
|
-
* persistent failure falls back to {@link DEFAULT_DECODER_BACKEND}.
|
|
34254
|
-
*
|
|
34255
|
-
* The OWNER addon must NOT call this (it would self-route + deadlock) — it uses
|
|
34256
|
-
* {@link resolveOwnDecoderBackend} against its own store instead.
|
|
34443
|
+
* Resolve the decoder backend this addon should run. Owner settings are
|
|
34444
|
+
* ignored: persisted `backend@<nodeId>` rows stay in the store and are not
|
|
34445
|
+
* consulted. The runtime default is always {@link DEFAULT_DECODER_BACKEND}.
|
|
34257
34446
|
*/
|
|
34258
|
-
async function resolveDecoderBackend(
|
|
34259
|
-
if (!api) {
|
|
34260
|
-
logger.warn("decoder-backend: no api surface — using default backend", { meta: { default: DEFAULT_DECODER_BACKEND } });
|
|
34261
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34262
|
-
}
|
|
34263
|
-
const normalized = normalizeDecoderNodeId(nodeId);
|
|
34264
|
-
const delaysMs = [
|
|
34265
|
-
150,
|
|
34266
|
-
350,
|
|
34267
|
-
600,
|
|
34268
|
-
900,
|
|
34269
|
-
1200
|
|
34270
|
-
];
|
|
34271
|
-
let lastErr;
|
|
34272
|
-
for (let attempt = 0; attempt <= delaysMs.length; attempt++) {
|
|
34273
|
-
try {
|
|
34274
|
-
const view = await api.addonSettings.getGlobalSettings.query({
|
|
34275
|
-
addonId: DECODER_OWNER_ADDON_ID,
|
|
34276
|
-
nodeId: normalized
|
|
34277
|
-
});
|
|
34278
|
-
if (view !== null) return pickDecoderBackendFromSettings(view);
|
|
34279
|
-
lastErr = /* @__PURE__ */ new Error("owner settings unavailable (null)");
|
|
34280
|
-
} catch (err) {
|
|
34281
|
-
lastErr = err;
|
|
34282
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
34283
|
-
if (isTransientSettingsError(msg)) {} else if (isMissingOwnerSettingsError(msg)) {
|
|
34284
|
-
logger.warn("decoder-backend: optional owner unavailable — using default backend", { meta: {
|
|
34285
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34286
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34287
|
-
error: msg
|
|
34288
|
-
} });
|
|
34289
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34290
|
-
} else {
|
|
34291
|
-
logger.warn("decoder-backend: settings read failed — using default backend", { meta: {
|
|
34292
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34293
|
-
error: msg
|
|
34294
|
-
} });
|
|
34295
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34296
|
-
}
|
|
34297
|
-
}
|
|
34298
|
-
if (attempt === delaysMs.length) break;
|
|
34299
|
-
await new Promise((resolve) => setTimeout(resolve, delaysMs[attempt]));
|
|
34300
|
-
}
|
|
34301
|
-
logger.warn("decoder-backend: owner settings unavailable after retries — using default backend", { meta: {
|
|
34302
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34303
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34304
|
-
error: lastErr instanceof Error ? lastErr.message : String(lastErr)
|
|
34305
|
-
} });
|
|
34447
|
+
async function resolveDecoderBackend(_api, _nodeId, _logger) {
|
|
34306
34448
|
return DEFAULT_DECODER_BACKEND;
|
|
34307
34449
|
}
|
|
34308
34450
|
//#endregion
|