@camstack/addon-decoder-nodeav 1.2.25 → 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 +252 -119
- package/dist/index.mjs +252 -119
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8020,6 +8020,15 @@ var LabelDefinitionSchema = object({
|
|
|
8020
8020
|
description: string().optional(),
|
|
8021
8021
|
icon: string().optional()
|
|
8022
8022
|
});
|
|
8023
|
+
var ClassMapDefinitionSchema = object({
|
|
8024
|
+
mapping: record(string(), _enum([
|
|
8025
|
+
"person",
|
|
8026
|
+
"vehicle",
|
|
8027
|
+
"animal",
|
|
8028
|
+
"package"
|
|
8029
|
+
])),
|
|
8030
|
+
preserveOriginal: boolean()
|
|
8031
|
+
});
|
|
8023
8032
|
var MODEL_FORMATS = [
|
|
8024
8033
|
"onnx",
|
|
8025
8034
|
"coreml",
|
|
@@ -8198,7 +8207,13 @@ var ModelCatalogEntrySchema = object({
|
|
|
8198
8207
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
8199
8208
|
* is a presentation overlay resolved back to an `id`.
|
|
8200
8209
|
*/
|
|
8201
|
-
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()
|
|
8202
8217
|
});
|
|
8203
8218
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8204
8219
|
format: literal("openvino"),
|
|
@@ -8227,7 +8242,8 @@ var ModelConvertMetadataSchema = object({
|
|
|
8227
8242
|
"ocr",
|
|
8228
8243
|
"segmentation"
|
|
8229
8244
|
]),
|
|
8230
|
-
faceAlignment: boolean().optional()
|
|
8245
|
+
faceAlignment: boolean().optional(),
|
|
8246
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8231
8247
|
});
|
|
8232
8248
|
var ConvertResultSchema = object({
|
|
8233
8249
|
entry: ModelCatalogEntrySchema,
|
|
@@ -17348,6 +17364,33 @@ var NativeCropRefSchema = object({
|
|
|
17348
17364
|
h: number()
|
|
17349
17365
|
})
|
|
17350
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
|
+
});
|
|
17351
17394
|
var ModelFormatSchema$1 = _enum([
|
|
17352
17395
|
"onnx",
|
|
17353
17396
|
"coreml",
|
|
@@ -17592,6 +17635,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
17592
17635
|
steps: array(PipelineStepInputSchema).min(1),
|
|
17593
17636
|
frame: FrameInputSchema.optional(),
|
|
17594
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
|
+
/**
|
|
17595
17644
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
17596
17645
|
* the decoded pixels live in. One more member of the one-of
|
|
17597
17646
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -17847,7 +17896,10 @@ var NativeCropResultSchema = object({
|
|
|
17847
17896
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
17848
17897
|
* `keyFrame`) can reject a degraded fallback:
|
|
17849
17898
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
17850
|
-
* 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`).
|
|
17851
17903
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
17852
17904
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
17853
17905
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -18338,12 +18390,41 @@ var RunnerLocalLoadSchema = object({
|
|
|
18338
18390
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
18339
18391
|
* working unchanged when they switch to reading from the runner cap.
|
|
18340
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
|
+
});
|
|
18341
18421
|
var RunnerLocalMetricsSchema = object({
|
|
18342
18422
|
nodeId: string(),
|
|
18343
18423
|
activeCameras: number(),
|
|
18344
18424
|
throttledCameras: number(),
|
|
18345
18425
|
avgInferenceTimeMs: number(),
|
|
18346
|
-
queueDepth: number()
|
|
18426
|
+
queueDepth: number(),
|
|
18427
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
18347
18428
|
});
|
|
18348
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({
|
|
18349
18430
|
handle: FrameHandleSchema,
|
|
@@ -19643,6 +19724,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
|
|
|
19643
19724
|
location: StorageLocationSchema,
|
|
19644
19725
|
relativePath: string()
|
|
19645
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());
|
|
19646
19730
|
/**
|
|
19647
19731
|
* A live terminal session hosted by the provider addon. Output and input do
|
|
19648
19732
|
* NOT flow through the capability — they use the addon data plane
|
|
@@ -19672,7 +19756,14 @@ var TerminalSessionInfoSchema = object({
|
|
|
19672
19756
|
var TerminalProfileInfoSchema = object({
|
|
19673
19757
|
profileId: string(),
|
|
19674
19758
|
label: string(),
|
|
19675
|
-
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()
|
|
19676
19767
|
});
|
|
19677
19768
|
/**
|
|
19678
19769
|
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
@@ -19685,7 +19776,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
19685
19776
|
profileId: string(),
|
|
19686
19777
|
profileLabel: string(),
|
|
19687
19778
|
name: string(),
|
|
19688
|
-
enabled: boolean()
|
|
19779
|
+
enabled: boolean(),
|
|
19780
|
+
executable: string(),
|
|
19781
|
+
args: array(string()).readonly(),
|
|
19782
|
+
cwd: string(),
|
|
19783
|
+
environment: array(string()).readonly(),
|
|
19784
|
+
profileSettings: ProfileSettingsBagSchema
|
|
19689
19785
|
});
|
|
19690
19786
|
var TerminalLegacyCameraSchema = object({
|
|
19691
19787
|
stableId: string(),
|
|
@@ -19715,7 +19811,23 @@ var TerminalOutputBatchSchema = object({
|
|
|
19715
19811
|
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19716
19812
|
targetNodeId: string().min(1),
|
|
19717
19813
|
profileId: string().min(1),
|
|
19718
|
-
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()
|
|
19719
19831
|
}), TerminalInstanceInfoSchema, {
|
|
19720
19832
|
kind: "mutation",
|
|
19721
19833
|
auth: "admin"
|
|
@@ -19737,7 +19849,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19737
19849
|
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19738
19850
|
profileId: string(),
|
|
19739
19851
|
cols: number().int().positive(),
|
|
19740
|
-
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()
|
|
19741
19857
|
}), TerminalSessionInfoSchema, {
|
|
19742
19858
|
kind: "mutation",
|
|
19743
19859
|
auth: "admin"
|
|
@@ -22519,10 +22635,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
|
|
|
22519
22635
|
*
|
|
22520
22636
|
* • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
|
|
22521
22637
|
* to receive an ordered list of candidate base URLs it should race
|
|
22522
|
-
* on connect — LAN IPv4 first (lowest latency
|
|
22523
|
-
* then public hostname (if a tunnel is
|
|
22524
|
-
* race them with short timeouts and stick with the
|
|
22525
|
-
* 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.
|
|
22526
22642
|
*
|
|
22527
22643
|
* Why hub-only: agents are not directly addressable by the operator's
|
|
22528
22644
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
@@ -22677,6 +22793,17 @@ var NotificationEndpointSchema = object({
|
|
|
22677
22793
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
22678
22794
|
resolved: string().nullable()
|
|
22679
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
|
+
});
|
|
22680
22807
|
var AllowedAddressesSchema = object({
|
|
22681
22808
|
/**
|
|
22682
22809
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -22685,6 +22812,20 @@ var AllowedAddressesSchema = object({
|
|
|
22685
22812
|
* Network Addresses admin page and persisted by the addon.
|
|
22686
22813
|
*/
|
|
22687
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
|
+
});
|
|
22688
22829
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
22689
22830
|
/**
|
|
22690
22831
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -22694,17 +22835,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
22694
22835
|
*/
|
|
22695
22836
|
port: number().int().min(1).max(65535).optional(),
|
|
22696
22837
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
22697
|
-
* candidate. Default `
|
|
22838
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
22698
22839
|
includeLoopback: boolean().optional(),
|
|
22699
|
-
/** Skip IPv6 entries.
|
|
22700
|
-
*
|
|
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`. */
|
|
22701
22843
|
ipv4Only: boolean().optional(),
|
|
22702
22844
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
22703
22845
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
22704
22846
|
* to avoid mixed-content blocks in the browser. The public
|
|
22705
22847
|
* tunnel always emits `https://` regardless. */
|
|
22706
22848
|
scheme: _enum(["http", "https"]).optional()
|
|
22707
|
-
}), 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
|
+
});
|
|
22708
22863
|
object({
|
|
22709
22864
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
22710
22865
|
* failure to reach the target — operator intervention required. */
|
|
@@ -28467,6 +28622,12 @@ Object.freeze({
|
|
|
28467
28622
|
addonId: null,
|
|
28468
28623
|
access: "create"
|
|
28469
28624
|
},
|
|
28625
|
+
"localNetwork.downloadCa": {
|
|
28626
|
+
capName: "local-network",
|
|
28627
|
+
capScope: "system",
|
|
28628
|
+
addonId: null,
|
|
28629
|
+
access: "view"
|
|
28630
|
+
},
|
|
28470
28631
|
"localNetwork.getAllowedAddresses": {
|
|
28471
28632
|
capName: "local-network",
|
|
28472
28633
|
capScope: "system",
|
|
@@ -28491,18 +28652,42 @@ Object.freeze({
|
|
|
28491
28652
|
addonId: null,
|
|
28492
28653
|
access: "view"
|
|
28493
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
|
+
},
|
|
28494
28667
|
"localNetwork.list": {
|
|
28495
28668
|
capName: "local-network",
|
|
28496
28669
|
capScope: "system",
|
|
28497
28670
|
addonId: null,
|
|
28498
28671
|
access: "view"
|
|
28499
28672
|
},
|
|
28673
|
+
"localNetwork.regenerateCertificate": {
|
|
28674
|
+
capName: "local-network",
|
|
28675
|
+
capScope: "system",
|
|
28676
|
+
addonId: null,
|
|
28677
|
+
access: "create"
|
|
28678
|
+
},
|
|
28500
28679
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
28501
28680
|
capName: "local-network",
|
|
28502
28681
|
capScope: "system",
|
|
28503
28682
|
addonId: null,
|
|
28504
28683
|
access: "delete"
|
|
28505
28684
|
},
|
|
28685
|
+
"localNetwork.revertToGeneratedCertificate": {
|
|
28686
|
+
capName: "local-network",
|
|
28687
|
+
capScope: "system",
|
|
28688
|
+
addonId: null,
|
|
28689
|
+
access: "create"
|
|
28690
|
+
},
|
|
28506
28691
|
"localNetwork.setAllowedAddresses": {
|
|
28507
28692
|
capName: "local-network",
|
|
28508
28693
|
capScope: "system",
|
|
@@ -28515,6 +28700,18 @@ Object.freeze({
|
|
|
28515
28700
|
addonId: null,
|
|
28516
28701
|
access: "create"
|
|
28517
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
|
+
},
|
|
28518
28715
|
"lockControl.lock": {
|
|
28519
28716
|
capName: "lock-control",
|
|
28520
28717
|
capScope: "device",
|
|
@@ -31395,6 +31592,12 @@ Object.freeze({
|
|
|
31395
31592
|
addonId: null,
|
|
31396
31593
|
access: "create"
|
|
31397
31594
|
},
|
|
31595
|
+
"terminalSession.updateInstance": {
|
|
31596
|
+
capName: "terminal-session",
|
|
31597
|
+
capScope: "system",
|
|
31598
|
+
addonId: null,
|
|
31599
|
+
access: "create"
|
|
31600
|
+
},
|
|
31398
31601
|
"terminalSession.writeInput": {
|
|
31399
31602
|
capName: "terminal-session",
|
|
31400
31603
|
capScope: "system",
|
|
@@ -33882,6 +34085,35 @@ Object.freeze(Object.fromEntries([{
|
|
|
33882
34085
|
}]
|
|
33883
34086
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
33884
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({});
|
|
33885
34117
|
object({
|
|
33886
34118
|
/**
|
|
33887
34119
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -34209,113 +34441,14 @@ var NotifyingRingBuffer = class {
|
|
|
34209
34441
|
* decoder is an explicit opt-in fallback only. A stale/failed settings read at
|
|
34210
34442
|
* boot therefore resolves to node-av (never leaves the node with no decoder). */
|
|
34211
34443
|
var DEFAULT_DECODER_BACKEND = "nodeav";
|
|
34212
|
-
/** Narrow an unknown settings value to a {@link DecoderBackend}, else `null`. */
|
|
34213
|
-
function parseDecoderBackend(value) {
|
|
34214
|
-
return value === "ffmpeg" || value === "nodeav" ? value : null;
|
|
34215
|
-
}
|
|
34216
|
-
/**
|
|
34217
|
-
* Normalise a raw kernel node id to the bare node id used for scoping.
|
|
34218
|
-
* `localNodeId` can carry a `<node>/<addon>` suffix; the decoder selection is
|
|
34219
|
-
* per-NODE, so strip the addon segment. Falls back to `hub`.
|
|
34220
|
-
*/
|
|
34221
|
-
function normalizeDecoderNodeId(rawNodeId) {
|
|
34222
|
-
const raw = rawNodeId ?? "hub";
|
|
34223
|
-
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
34224
|
-
}
|
|
34225
34444
|
//#endregion
|
|
34226
34445
|
//#region src/shared/decoder-backend.ts
|
|
34227
|
-
/** The NEUTRAL addon (pipeline-orchestrator, hub-resident) whose global
|
|
34228
|
-
* settings OWN the per-node `backend` selector. Neither decoder addon owns
|
|
34229
|
-
* it, so decoder-nodeav / decoder-ffmpeg stay fully independent. */
|
|
34230
|
-
var DECODER_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
34231
|
-
function isHydratedField(entry) {
|
|
34232
|
-
return typeof entry === "object" && entry !== null && "key" in entry;
|
|
34233
|
-
}
|
|
34234
34446
|
/**
|
|
34235
|
-
*
|
|
34236
|
-
*
|
|
34237
|
-
*
|
|
34238
|
-
* resolves to {@link DEFAULT_DECODER_BACKEND} — never a bare store key.
|
|
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}.
|
|
34239
34450
|
*/
|
|
34240
|
-
function
|
|
34241
|
-
if (view === null) return DEFAULT_DECODER_BACKEND;
|
|
34242
|
-
for (const section of view.sections) for (const entry of section.fields) {
|
|
34243
|
-
if (!isHydratedField(entry) || entry.key !== "backend") continue;
|
|
34244
|
-
return parseDecoderBackend(entry.value) ?? "nodeav";
|
|
34245
|
-
}
|
|
34246
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34247
|
-
}
|
|
34248
|
-
/** Missing optional owner fingerprints: ffmpeg may be uninstalled. */
|
|
34249
|
-
function isMissingOwnerSettingsError(message) {
|
|
34250
|
-
return /not routable/i.test(message) || /provider not available/i.test(message);
|
|
34251
|
-
}
|
|
34252
|
-
/** Transient transport/settings-store fingerprints worth retrying on. */
|
|
34253
|
-
function isTransientSettingsError(message) {
|
|
34254
|
-
return /not loaded/i.test(message) || /transport-failed/i.test(message) || /not connected/i.test(message) || /SqliteSettingsBackend not initialized/i.test(message);
|
|
34255
|
-
}
|
|
34256
|
-
/**
|
|
34257
|
-
* Resolve the decoder backend a NON-OWNER addon (`decoder-nodeav`) should run,
|
|
34258
|
-
* by reading the OWNER's (`decoder-ffmpeg`) hub-central per-node `backend`.
|
|
34259
|
-
*
|
|
34260
|
-
* The read routes to the owner addon's child runner; during a simultaneous
|
|
34261
|
-
* (re)start the owner may not be up yet → a transient `transport-failed (addon
|
|
34262
|
-
* not loaded)`. Immediately defaulting here would ignore an explicit `ffmpeg`
|
|
34263
|
-
* selection (the node would silently run the node-av default instead). So retry
|
|
34264
|
-
* on the transient fingerprints with a bounded budget (mirrors
|
|
34265
|
-
* `BaseAddon.readAddonStoreWithRetry`) until the owner answers; only a
|
|
34266
|
-
* persistent failure falls back to {@link DEFAULT_DECODER_BACKEND}.
|
|
34267
|
-
*
|
|
34268
|
-
* The OWNER addon must NOT call this (it would self-route + deadlock) — it uses
|
|
34269
|
-
* {@link resolveOwnDecoderBackend} against its own store instead.
|
|
34270
|
-
*/
|
|
34271
|
-
async function resolveDecoderBackend(api, nodeId, logger) {
|
|
34272
|
-
if (!api) {
|
|
34273
|
-
logger.warn("decoder-backend: no api surface — using default backend", { meta: { default: DEFAULT_DECODER_BACKEND } });
|
|
34274
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34275
|
-
}
|
|
34276
|
-
const normalized = normalizeDecoderNodeId(nodeId);
|
|
34277
|
-
const delaysMs = [
|
|
34278
|
-
150,
|
|
34279
|
-
350,
|
|
34280
|
-
600,
|
|
34281
|
-
900,
|
|
34282
|
-
1200
|
|
34283
|
-
];
|
|
34284
|
-
let lastErr;
|
|
34285
|
-
for (let attempt = 0; attempt <= delaysMs.length; attempt++) {
|
|
34286
|
-
try {
|
|
34287
|
-
const view = await api.addonSettings.getGlobalSettings.query({
|
|
34288
|
-
addonId: DECODER_OWNER_ADDON_ID,
|
|
34289
|
-
nodeId: normalized
|
|
34290
|
-
});
|
|
34291
|
-
if (view !== null) return pickDecoderBackendFromSettings(view);
|
|
34292
|
-
lastErr = /* @__PURE__ */ new Error("owner settings unavailable (null)");
|
|
34293
|
-
} catch (err) {
|
|
34294
|
-
lastErr = err;
|
|
34295
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
34296
|
-
if (isTransientSettingsError(msg)) {} else if (isMissingOwnerSettingsError(msg)) {
|
|
34297
|
-
logger.warn("decoder-backend: optional owner unavailable — using default backend", { meta: {
|
|
34298
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34299
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34300
|
-
error: msg
|
|
34301
|
-
} });
|
|
34302
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34303
|
-
} else {
|
|
34304
|
-
logger.warn("decoder-backend: settings read failed — using default backend", { meta: {
|
|
34305
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34306
|
-
error: msg
|
|
34307
|
-
} });
|
|
34308
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34309
|
-
}
|
|
34310
|
-
}
|
|
34311
|
-
if (attempt === delaysMs.length) break;
|
|
34312
|
-
await new Promise((resolve) => setTimeout(resolve, delaysMs[attempt]));
|
|
34313
|
-
}
|
|
34314
|
-
logger.warn("decoder-backend: owner settings unavailable after retries — using default backend", { meta: {
|
|
34315
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34316
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34317
|
-
error: lastErr instanceof Error ? lastErr.message : String(lastErr)
|
|
34318
|
-
} });
|
|
34451
|
+
async function resolveDecoderBackend(_api, _nodeId, _logger) {
|
|
34319
34452
|
return DEFAULT_DECODER_BACKEND;
|
|
34320
34453
|
}
|
|
34321
34454
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -8016,6 +8016,15 @@ var LabelDefinitionSchema = object({
|
|
|
8016
8016
|
description: string().optional(),
|
|
8017
8017
|
icon: string().optional()
|
|
8018
8018
|
});
|
|
8019
|
+
var ClassMapDefinitionSchema = object({
|
|
8020
|
+
mapping: record(string(), _enum([
|
|
8021
|
+
"person",
|
|
8022
|
+
"vehicle",
|
|
8023
|
+
"animal",
|
|
8024
|
+
"package"
|
|
8025
|
+
])),
|
|
8026
|
+
preserveOriginal: boolean()
|
|
8027
|
+
});
|
|
8019
8028
|
var MODEL_FORMATS = [
|
|
8020
8029
|
"onnx",
|
|
8021
8030
|
"coreml",
|
|
@@ -8194,7 +8203,13 @@ var ModelCatalogEntrySchema = object({
|
|
|
8194
8203
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
8195
8204
|
* is a presentation overlay resolved back to an `id`.
|
|
8196
8205
|
*/
|
|
8197
|
-
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()
|
|
8198
8213
|
});
|
|
8199
8214
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8200
8215
|
format: literal("openvino"),
|
|
@@ -8223,7 +8238,8 @@ var ModelConvertMetadataSchema = object({
|
|
|
8223
8238
|
"ocr",
|
|
8224
8239
|
"segmentation"
|
|
8225
8240
|
]),
|
|
8226
|
-
faceAlignment: boolean().optional()
|
|
8241
|
+
faceAlignment: boolean().optional(),
|
|
8242
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
8227
8243
|
});
|
|
8228
8244
|
var ConvertResultSchema = object({
|
|
8229
8245
|
entry: ModelCatalogEntrySchema,
|
|
@@ -17344,6 +17360,33 @@ var NativeCropRefSchema = object({
|
|
|
17344
17360
|
h: number()
|
|
17345
17361
|
})
|
|
17346
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
|
+
});
|
|
17347
17390
|
var ModelFormatSchema$1 = _enum([
|
|
17348
17391
|
"onnx",
|
|
17349
17392
|
"coreml",
|
|
@@ -17588,6 +17631,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
17588
17631
|
steps: array(PipelineStepInputSchema).min(1),
|
|
17589
17632
|
frame: FrameInputSchema.optional(),
|
|
17590
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
|
+
/**
|
|
17591
17640
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
17592
17641
|
* the decoded pixels live in. One more member of the one-of
|
|
17593
17642
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -17843,7 +17892,10 @@ var NativeCropResultSchema = object({
|
|
|
17843
17892
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
17844
17893
|
* `keyFrame`) can reject a degraded fallback:
|
|
17845
17894
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
17846
|
-
* 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`).
|
|
17847
17899
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
17848
17900
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
17849
17901
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -18334,12 +18386,41 @@ var RunnerLocalLoadSchema = object({
|
|
|
18334
18386
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
18335
18387
|
* working unchanged when they switch to reading from the runner cap.
|
|
18336
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
|
+
});
|
|
18337
18417
|
var RunnerLocalMetricsSchema = object({
|
|
18338
18418
|
nodeId: string(),
|
|
18339
18419
|
activeCameras: number(),
|
|
18340
18420
|
throttledCameras: number(),
|
|
18341
18421
|
avgInferenceTimeMs: number(),
|
|
18342
|
-
queueDepth: number()
|
|
18422
|
+
queueDepth: number(),
|
|
18423
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
18343
18424
|
});
|
|
18344
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({
|
|
18345
18426
|
handle: FrameHandleSchema,
|
|
@@ -19639,6 +19720,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
|
|
|
19639
19720
|
location: StorageLocationSchema,
|
|
19640
19721
|
relativePath: string()
|
|
19641
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());
|
|
19642
19726
|
/**
|
|
19643
19727
|
* A live terminal session hosted by the provider addon. Output and input do
|
|
19644
19728
|
* NOT flow through the capability — they use the addon data plane
|
|
@@ -19668,7 +19752,14 @@ var TerminalSessionInfoSchema = object({
|
|
|
19668
19752
|
var TerminalProfileInfoSchema = object({
|
|
19669
19753
|
profileId: string(),
|
|
19670
19754
|
label: string(),
|
|
19671
|
-
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()
|
|
19672
19763
|
});
|
|
19673
19764
|
/**
|
|
19674
19765
|
* A durable operator-created Terminal instance. Profiles are templates; only
|
|
@@ -19681,7 +19772,12 @@ var TerminalInstanceInfoSchema = object({
|
|
|
19681
19772
|
profileId: string(),
|
|
19682
19773
|
profileLabel: string(),
|
|
19683
19774
|
name: string(),
|
|
19684
|
-
enabled: boolean()
|
|
19775
|
+
enabled: boolean(),
|
|
19776
|
+
executable: string(),
|
|
19777
|
+
args: array(string()).readonly(),
|
|
19778
|
+
cwd: string(),
|
|
19779
|
+
environment: array(string()).readonly(),
|
|
19780
|
+
profileSettings: ProfileSettingsBagSchema
|
|
19685
19781
|
});
|
|
19686
19782
|
var TerminalLegacyCameraSchema = object({
|
|
19687
19783
|
stableId: string(),
|
|
@@ -19711,7 +19807,23 @@ var TerminalOutputBatchSchema = object({
|
|
|
19711
19807
|
method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19712
19808
|
targetNodeId: string().min(1),
|
|
19713
19809
|
profileId: string().min(1),
|
|
19714
|
-
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()
|
|
19715
19827
|
}), TerminalInstanceInfoSchema, {
|
|
19716
19828
|
kind: "mutation",
|
|
19717
19829
|
auth: "admin"
|
|
@@ -19733,7 +19845,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
|
|
|
19733
19845
|
}), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
19734
19846
|
profileId: string(),
|
|
19735
19847
|
cols: number().int().positive(),
|
|
19736
|
-
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()
|
|
19737
19853
|
}), TerminalSessionInfoSchema, {
|
|
19738
19854
|
kind: "mutation",
|
|
19739
19855
|
auth: "admin"
|
|
@@ -22515,10 +22631,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
|
|
|
22515
22631
|
*
|
|
22516
22632
|
* • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
|
|
22517
22633
|
* to receive an ordered list of candidate base URLs it should race
|
|
22518
|
-
* on connect — LAN IPv4 first (lowest latency
|
|
22519
|
-
* then public hostname (if a tunnel is
|
|
22520
|
-
* race them with short timeouts and stick with the
|
|
22521
|
-
* 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.
|
|
22522
22638
|
*
|
|
22523
22639
|
* Why hub-only: agents are not directly addressable by the operator's
|
|
22524
22640
|
* clients — they reverse-connect to the hub. Exposing their interfaces
|
|
@@ -22673,6 +22789,17 @@ var NotificationEndpointSchema = object({
|
|
|
22673
22789
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
22674
22790
|
resolved: string().nullable()
|
|
22675
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
|
+
});
|
|
22676
22803
|
var AllowedAddressesSchema = object({
|
|
22677
22804
|
/**
|
|
22678
22805
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -22681,6 +22808,20 @@ var AllowedAddressesSchema = object({
|
|
|
22681
22808
|
* Network Addresses admin page and persisted by the addon.
|
|
22682
22809
|
*/
|
|
22683
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
|
+
});
|
|
22684
22825
|
method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
|
|
22685
22826
|
/**
|
|
22686
22827
|
* LEGACY HINT — do not send from new code. Kept optional so clients
|
|
@@ -22690,17 +22831,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
22690
22831
|
*/
|
|
22691
22832
|
port: number().int().min(1).max(65535).optional(),
|
|
22692
22833
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
22693
|
-
* candidate. Default `
|
|
22834
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
22694
22835
|
includeLoopback: boolean().optional(),
|
|
22695
|
-
/** Skip IPv6 entries.
|
|
22696
|
-
*
|
|
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`. */
|
|
22697
22839
|
ipv4Only: boolean().optional(),
|
|
22698
22840
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
22699
22841
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
22700
22842
|
* to avoid mixed-content blocks in the browser. The public
|
|
22701
22843
|
* tunnel always emits `https://` regardless. */
|
|
22702
22844
|
scheme: _enum(["http", "https"]).optional()
|
|
22703
|
-
}), 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
|
+
});
|
|
22704
22859
|
object({
|
|
22705
22860
|
/** Lifecycle state of the lock. `jammed` means the motor reported
|
|
22706
22861
|
* failure to reach the target — operator intervention required. */
|
|
@@ -28463,6 +28618,12 @@ Object.freeze({
|
|
|
28463
28618
|
addonId: null,
|
|
28464
28619
|
access: "create"
|
|
28465
28620
|
},
|
|
28621
|
+
"localNetwork.downloadCa": {
|
|
28622
|
+
capName: "local-network",
|
|
28623
|
+
capScope: "system",
|
|
28624
|
+
addonId: null,
|
|
28625
|
+
access: "view"
|
|
28626
|
+
},
|
|
28466
28627
|
"localNetwork.getAllowedAddresses": {
|
|
28467
28628
|
capName: "local-network",
|
|
28468
28629
|
capScope: "system",
|
|
@@ -28487,18 +28648,42 @@ Object.freeze({
|
|
|
28487
28648
|
addonId: null,
|
|
28488
28649
|
access: "view"
|
|
28489
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
|
+
},
|
|
28490
28663
|
"localNetwork.list": {
|
|
28491
28664
|
capName: "local-network",
|
|
28492
28665
|
capScope: "system",
|
|
28493
28666
|
addonId: null,
|
|
28494
28667
|
access: "view"
|
|
28495
28668
|
},
|
|
28669
|
+
"localNetwork.regenerateCertificate": {
|
|
28670
|
+
capName: "local-network",
|
|
28671
|
+
capScope: "system",
|
|
28672
|
+
addonId: null,
|
|
28673
|
+
access: "create"
|
|
28674
|
+
},
|
|
28496
28675
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
28497
28676
|
capName: "local-network",
|
|
28498
28677
|
capScope: "system",
|
|
28499
28678
|
addonId: null,
|
|
28500
28679
|
access: "delete"
|
|
28501
28680
|
},
|
|
28681
|
+
"localNetwork.revertToGeneratedCertificate": {
|
|
28682
|
+
capName: "local-network",
|
|
28683
|
+
capScope: "system",
|
|
28684
|
+
addonId: null,
|
|
28685
|
+
access: "create"
|
|
28686
|
+
},
|
|
28502
28687
|
"localNetwork.setAllowedAddresses": {
|
|
28503
28688
|
capName: "local-network",
|
|
28504
28689
|
capScope: "system",
|
|
@@ -28511,6 +28696,18 @@ Object.freeze({
|
|
|
28511
28696
|
addonId: null,
|
|
28512
28697
|
access: "create"
|
|
28513
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
|
+
},
|
|
28514
28711
|
"lockControl.lock": {
|
|
28515
28712
|
capName: "lock-control",
|
|
28516
28713
|
capScope: "device",
|
|
@@ -31391,6 +31588,12 @@ Object.freeze({
|
|
|
31391
31588
|
addonId: null,
|
|
31392
31589
|
access: "create"
|
|
31393
31590
|
},
|
|
31591
|
+
"terminalSession.updateInstance": {
|
|
31592
|
+
capName: "terminal-session",
|
|
31593
|
+
capScope: "system",
|
|
31594
|
+
addonId: null,
|
|
31595
|
+
access: "create"
|
|
31596
|
+
},
|
|
31394
31597
|
"terminalSession.writeInput": {
|
|
31395
31598
|
capName: "terminal-session",
|
|
31396
31599
|
capScope: "system",
|
|
@@ -33878,6 +34081,35 @@ Object.freeze(Object.fromEntries([{
|
|
|
33878
34081
|
}]
|
|
33879
34082
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
33880
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({});
|
|
33881
34113
|
object({
|
|
33882
34114
|
/**
|
|
33883
34115
|
* Fraction of the box's own size added on EACH side before cutting.
|
|
@@ -34205,113 +34437,14 @@ var NotifyingRingBuffer = class {
|
|
|
34205
34437
|
* decoder is an explicit opt-in fallback only. A stale/failed settings read at
|
|
34206
34438
|
* boot therefore resolves to node-av (never leaves the node with no decoder). */
|
|
34207
34439
|
var DEFAULT_DECODER_BACKEND = "nodeav";
|
|
34208
|
-
/** Narrow an unknown settings value to a {@link DecoderBackend}, else `null`. */
|
|
34209
|
-
function parseDecoderBackend(value) {
|
|
34210
|
-
return value === "ffmpeg" || value === "nodeav" ? value : null;
|
|
34211
|
-
}
|
|
34212
|
-
/**
|
|
34213
|
-
* Normalise a raw kernel node id to the bare node id used for scoping.
|
|
34214
|
-
* `localNodeId` can carry a `<node>/<addon>` suffix; the decoder selection is
|
|
34215
|
-
* per-NODE, so strip the addon segment. Falls back to `hub`.
|
|
34216
|
-
*/
|
|
34217
|
-
function normalizeDecoderNodeId(rawNodeId) {
|
|
34218
|
-
const raw = rawNodeId ?? "hub";
|
|
34219
|
-
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
34220
|
-
}
|
|
34221
34440
|
//#endregion
|
|
34222
34441
|
//#region src/shared/decoder-backend.ts
|
|
34223
|
-
/** The NEUTRAL addon (pipeline-orchestrator, hub-resident) whose global
|
|
34224
|
-
* settings OWN the per-node `backend` selector. Neither decoder addon owns
|
|
34225
|
-
* it, so decoder-nodeav / decoder-ffmpeg stay fully independent. */
|
|
34226
|
-
var DECODER_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
34227
|
-
function isHydratedField(entry) {
|
|
34228
|
-
return typeof entry === "object" && entry !== null && "key" in entry;
|
|
34229
|
-
}
|
|
34230
34442
|
/**
|
|
34231
|
-
*
|
|
34232
|
-
*
|
|
34233
|
-
*
|
|
34234
|
-
* resolves to {@link DEFAULT_DECODER_BACKEND} — never a bare store key.
|
|
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}.
|
|
34235
34446
|
*/
|
|
34236
|
-
function
|
|
34237
|
-
if (view === null) return DEFAULT_DECODER_BACKEND;
|
|
34238
|
-
for (const section of view.sections) for (const entry of section.fields) {
|
|
34239
|
-
if (!isHydratedField(entry) || entry.key !== "backend") continue;
|
|
34240
|
-
return parseDecoderBackend(entry.value) ?? "nodeav";
|
|
34241
|
-
}
|
|
34242
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34243
|
-
}
|
|
34244
|
-
/** Missing optional owner fingerprints: ffmpeg may be uninstalled. */
|
|
34245
|
-
function isMissingOwnerSettingsError(message) {
|
|
34246
|
-
return /not routable/i.test(message) || /provider not available/i.test(message);
|
|
34247
|
-
}
|
|
34248
|
-
/** Transient transport/settings-store fingerprints worth retrying on. */
|
|
34249
|
-
function isTransientSettingsError(message) {
|
|
34250
|
-
return /not loaded/i.test(message) || /transport-failed/i.test(message) || /not connected/i.test(message) || /SqliteSettingsBackend not initialized/i.test(message);
|
|
34251
|
-
}
|
|
34252
|
-
/**
|
|
34253
|
-
* Resolve the decoder backend a NON-OWNER addon (`decoder-nodeav`) should run,
|
|
34254
|
-
* by reading the OWNER's (`decoder-ffmpeg`) hub-central per-node `backend`.
|
|
34255
|
-
*
|
|
34256
|
-
* The read routes to the owner addon's child runner; during a simultaneous
|
|
34257
|
-
* (re)start the owner may not be up yet → a transient `transport-failed (addon
|
|
34258
|
-
* not loaded)`. Immediately defaulting here would ignore an explicit `ffmpeg`
|
|
34259
|
-
* selection (the node would silently run the node-av default instead). So retry
|
|
34260
|
-
* on the transient fingerprints with a bounded budget (mirrors
|
|
34261
|
-
* `BaseAddon.readAddonStoreWithRetry`) until the owner answers; only a
|
|
34262
|
-
* persistent failure falls back to {@link DEFAULT_DECODER_BACKEND}.
|
|
34263
|
-
*
|
|
34264
|
-
* The OWNER addon must NOT call this (it would self-route + deadlock) — it uses
|
|
34265
|
-
* {@link resolveOwnDecoderBackend} against its own store instead.
|
|
34266
|
-
*/
|
|
34267
|
-
async function resolveDecoderBackend(api, nodeId, logger) {
|
|
34268
|
-
if (!api) {
|
|
34269
|
-
logger.warn("decoder-backend: no api surface — using default backend", { meta: { default: DEFAULT_DECODER_BACKEND } });
|
|
34270
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34271
|
-
}
|
|
34272
|
-
const normalized = normalizeDecoderNodeId(nodeId);
|
|
34273
|
-
const delaysMs = [
|
|
34274
|
-
150,
|
|
34275
|
-
350,
|
|
34276
|
-
600,
|
|
34277
|
-
900,
|
|
34278
|
-
1200
|
|
34279
|
-
];
|
|
34280
|
-
let lastErr;
|
|
34281
|
-
for (let attempt = 0; attempt <= delaysMs.length; attempt++) {
|
|
34282
|
-
try {
|
|
34283
|
-
const view = await api.addonSettings.getGlobalSettings.query({
|
|
34284
|
-
addonId: DECODER_OWNER_ADDON_ID,
|
|
34285
|
-
nodeId: normalized
|
|
34286
|
-
});
|
|
34287
|
-
if (view !== null) return pickDecoderBackendFromSettings(view);
|
|
34288
|
-
lastErr = /* @__PURE__ */ new Error("owner settings unavailable (null)");
|
|
34289
|
-
} catch (err) {
|
|
34290
|
-
lastErr = err;
|
|
34291
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
34292
|
-
if (isTransientSettingsError(msg)) {} else if (isMissingOwnerSettingsError(msg)) {
|
|
34293
|
-
logger.warn("decoder-backend: optional owner unavailable — using default backend", { meta: {
|
|
34294
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34295
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34296
|
-
error: msg
|
|
34297
|
-
} });
|
|
34298
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34299
|
-
} else {
|
|
34300
|
-
logger.warn("decoder-backend: settings read failed — using default backend", { meta: {
|
|
34301
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34302
|
-
error: msg
|
|
34303
|
-
} });
|
|
34304
|
-
return DEFAULT_DECODER_BACKEND;
|
|
34305
|
-
}
|
|
34306
|
-
}
|
|
34307
|
-
if (attempt === delaysMs.length) break;
|
|
34308
|
-
await new Promise((resolve) => setTimeout(resolve, delaysMs[attempt]));
|
|
34309
|
-
}
|
|
34310
|
-
logger.warn("decoder-backend: owner settings unavailable after retries — using default backend", { meta: {
|
|
34311
|
-
default: DEFAULT_DECODER_BACKEND,
|
|
34312
|
-
owner: DECODER_OWNER_ADDON_ID,
|
|
34313
|
-
error: lastErr instanceof Error ? lastErr.message : String(lastErr)
|
|
34314
|
-
} });
|
|
34447
|
+
async function resolveDecoderBackend(_api, _nodeId, _logger) {
|
|
34315
34448
|
return DEFAULT_DECODER_BACKEND;
|
|
34316
34449
|
}
|
|
34317
34450
|
//#endregion
|