@camstack/system 1.2.117 → 1.2.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/addon-utils.d.ts +1 -1
- package/dist/addon-utils.js +1 -1
- package/dist/addon-utils.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.d.ts +24 -2
- package/dist/builtins/local-network/local-network.addon.js +63 -17
- package/dist/builtins/local-network/local-network.addon.mjs +62 -18
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-DMEGlqg6.js → dist-CX9qXYC4.js} +247 -26
- package/dist/{dist-D4Vmj8iw.mjs → dist-DNbsZxNv.mjs} +247 -26
- package/dist/download/model-downloader.d.ts +18 -1
- package/dist/{file-data-plane-CuE_hBli.mjs → file-data-plane-BhKdxJgf.mjs} +49 -13
- package/dist/{file-data-plane-DUHPHa-Y.js → file-data-plane-DO8KbxCe.js} +49 -13
- package/dist/index.js +171 -10
- package/dist/index.mjs +170 -12
- package/dist/kernel/config-manager.d.ts +8 -1
- package/dist/kernel/index.d.ts +3 -0
- package/dist/kernel/isolated-builtin-phase.d.ts +21 -0
- package/dist/kernel/settings-door-view.d.ts +7 -0
- package/dist/{manifest-python-deps-CwBbX4Ut.js → manifest-python-deps-76dZLxD0.js} +11 -3
- package/dist/{manifest-python-deps-SGdbr9D5.mjs → manifest-python-deps-DZSNlHjU.mjs} +12 -4
- package/dist/{retired-settings-keys-DET4YkAU.js → retired-settings-keys-DlIuGG4o.js} +1 -1
- package/dist/{retired-settings-keys--aM_vGF9.mjs → retired-settings-keys-Dt0-obcq.mjs} +1 -1
- package/package.json +6 -2
|
@@ -4123,6 +4123,15 @@ var LabelDefinitionSchema = z.object({
|
|
|
4123
4123
|
description: z.string().optional(),
|
|
4124
4124
|
icon: z.string().optional()
|
|
4125
4125
|
});
|
|
4126
|
+
var ClassMapDefinitionSchema = z.object({
|
|
4127
|
+
mapping: z.record(z.string(), z.enum([
|
|
4128
|
+
"person",
|
|
4129
|
+
"vehicle",
|
|
4130
|
+
"animal",
|
|
4131
|
+
"package"
|
|
4132
|
+
])),
|
|
4133
|
+
preserveOriginal: z.boolean()
|
|
4134
|
+
});
|
|
4126
4135
|
var MODEL_FORMATS = [
|
|
4127
4136
|
"onnx",
|
|
4128
4137
|
"coreml",
|
|
@@ -4206,6 +4215,12 @@ var ModelVariantGroupSchema = z.object({
|
|
|
4206
4215
|
*/
|
|
4207
4216
|
resolution: z.number().int().positive().optional()
|
|
4208
4217
|
});
|
|
4218
|
+
var ModelProviderIdSchema = z.enum([
|
|
4219
|
+
"camstack",
|
|
4220
|
+
"frigate",
|
|
4221
|
+
"scrypted",
|
|
4222
|
+
"custom"
|
|
4223
|
+
]);
|
|
4209
4224
|
var ModelCatalogEntrySchema = z.object({
|
|
4210
4225
|
id: z.string(),
|
|
4211
4226
|
name: z.string(),
|
|
@@ -4301,7 +4316,19 @@ var ModelCatalogEntrySchema = z.object({
|
|
|
4301
4316
|
* `id` stays the source of truth for resolution/download/persistence; grouping
|
|
4302
4317
|
* is a presentation overlay resolved back to an `id`.
|
|
4303
4318
|
*/
|
|
4304
|
-
group: ModelVariantGroupSchema.optional()
|
|
4319
|
+
group: ModelVariantGroupSchema.optional(),
|
|
4320
|
+
/**
|
|
4321
|
+
* Catalog source for the pipeline stepper's provider-first picker. Absent on
|
|
4322
|
+
* built-in CamStack entries (treated as `camstack`) and on registry rows
|
|
4323
|
+
* persisted before this field existed (`inferModelProvider` fills those).
|
|
4324
|
+
*/
|
|
4325
|
+
provider: ModelProviderIdSchema.optional(),
|
|
4326
|
+
/**
|
|
4327
|
+
* Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
|
|
4328
|
+
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
4329
|
+
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
4330
|
+
*/
|
|
4331
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
4305
4332
|
});
|
|
4306
4333
|
var ConvertTargetSchema = z.discriminatedUnion("format", [z.object({
|
|
4307
4334
|
format: z.literal("openvino"),
|
|
@@ -4330,7 +4357,8 @@ var ModelConvertMetadataSchema = z.object({
|
|
|
4330
4357
|
"ocr",
|
|
4331
4358
|
"segmentation"
|
|
4332
4359
|
]),
|
|
4333
|
-
faceAlignment: z.boolean().optional()
|
|
4360
|
+
faceAlignment: z.boolean().optional(),
|
|
4361
|
+
classMap: ClassMapDefinitionSchema.optional()
|
|
4334
4362
|
});
|
|
4335
4363
|
var ConvertArtifactSchema = z.object({
|
|
4336
4364
|
format: z.enum(MODEL_FORMATS),
|
|
@@ -12556,12 +12584,15 @@ var NcOccupancyConditionSchema = z.object({
|
|
|
12556
12584
|
* there is no second switch that can disagree with the first and every rule
|
|
12557
12585
|
* authored before the decision migrates for free (`audioModeOf`):
|
|
12558
12586
|
*
|
|
12559
|
-
* - **LABEL mode — `labels` present.** The rule fires
|
|
12560
|
-
*
|
|
12561
|
-
* `hitPercent` and `samplingSeconds` are ignored
|
|
12562
|
-
*
|
|
12563
|
-
*
|
|
12564
|
-
*
|
|
12587
|
+
* - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
|
|
12588
|
+
* labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
|
|
12589
|
+
* `hitPercent` and `samplingSeconds` are still ignored — a percentage of
|
|
12590
|
+
* frames is the wrong question for a classifier that labels 1–3 frames
|
|
12591
|
+
* per episode. The count window is the brake that drops a single-frame
|
|
12592
|
+
* false positive; the rule's own `throttle` cooldown is the other. The
|
|
12593
|
+
* per-label confidence floor is the analyzer's (`classificationMinScore`,
|
|
12594
|
+
* per device) — a label only reaches this condition if the classifier was
|
|
12595
|
+
* already confident enough. `confirmHits: 1` restores first-frame fire.
|
|
12565
12596
|
* - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
|
|
12566
12597
|
* the condition: at least `hitPercent`% of the samples over
|
|
12567
12598
|
* `samplingSeconds` must be at or above `dbThreshold` dBFS (see
|
|
@@ -12588,14 +12619,22 @@ var NcOccupancyConditionSchema = z.object({
|
|
|
12588
12619
|
* an operator who typed `dog` mean the same thing.
|
|
12589
12620
|
*/
|
|
12590
12621
|
var NcAudioConditionSchema = z.object({
|
|
12591
|
-
/** LABEL MODE: audio macro labels. Present ⇒
|
|
12622
|
+
/** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
|
|
12592
12623
|
labels: z.array(z.string().min(1)).min(1).optional(),
|
|
12593
12624
|
/** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
|
|
12594
12625
|
dbThreshold: z.number().min(-96).max(0).optional(),
|
|
12595
12626
|
/** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
|
|
12596
12627
|
hitPercent: z.number().int().min(1).max(100).default(60),
|
|
12597
12628
|
/** LEVEL MODE ONLY: length of the sampling window in seconds. */
|
|
12598
|
-
samplingSeconds: z.number().int().min(1).max(300).default(10)
|
|
12629
|
+
samplingSeconds: z.number().int().min(1).max(300).default(10),
|
|
12630
|
+
/**
|
|
12631
|
+
* LABEL MODE: how many labelled frames must land inside
|
|
12632
|
+
* {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
|
|
12633
|
+
* Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
|
|
12634
|
+
*/
|
|
12635
|
+
confirmHits: z.number().int().min(1).max(20).optional(),
|
|
12636
|
+
/** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
|
|
12637
|
+
confirmWindowSec: z.number().int().min(1).max(60).optional()
|
|
12599
12638
|
});
|
|
12600
12639
|
/**
|
|
12601
12640
|
* Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
|
|
@@ -15085,6 +15124,46 @@ var RecentTracksPageSchema = z.object({
|
|
|
15085
15124
|
/** Cursor for the next page, or null when this page is the last. */
|
|
15086
15125
|
nextCursor: z.string().nullable()
|
|
15087
15126
|
});
|
|
15127
|
+
var LIST_GROUPS_DEFAULT_LIMIT = 40;
|
|
15128
|
+
var LIST_GROUPS_MAX_LIMIT = 100;
|
|
15129
|
+
var AnalyticsGroupRecordSchema = z.object({
|
|
15130
|
+
id: z.string(),
|
|
15131
|
+
deviceId: z.number().int(),
|
|
15132
|
+
openedAt: z.number().int(),
|
|
15133
|
+
closedAt: z.number().int(),
|
|
15134
|
+
timestamp: z.number().int(),
|
|
15135
|
+
memberCount: z.number().int(),
|
|
15136
|
+
memberTrackIds: z.array(z.string()).readonly(),
|
|
15137
|
+
className: z.string(),
|
|
15138
|
+
classes: z.array(z.string()).readonly(),
|
|
15139
|
+
/** Relative event-media path, or null when the group has no picture yet. */
|
|
15140
|
+
mediaUrl: z.string().nullable(),
|
|
15141
|
+
singleton: z.boolean()
|
|
15142
|
+
});
|
|
15143
|
+
var AnalyticsGroupMemberSchema = z.object({
|
|
15144
|
+
trackId: z.string(),
|
|
15145
|
+
deviceId: z.number().int(),
|
|
15146
|
+
className: z.string(),
|
|
15147
|
+
firstSeen: z.number().int(),
|
|
15148
|
+
lastSeen: z.number().int(),
|
|
15149
|
+
mediaUrl: z.string().nullable()
|
|
15150
|
+
});
|
|
15151
|
+
var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: z.array(AnalyticsGroupMemberSchema).readonly() });
|
|
15152
|
+
var ListGroupsQueryInput = z.object({
|
|
15153
|
+
/** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
|
|
15154
|
+
deviceIds: z.array(z.number()),
|
|
15155
|
+
/** Window lower bound on `closedAt` (inclusive). */
|
|
15156
|
+
since: z.number().optional(),
|
|
15157
|
+
/** Window upper bound on `openedAt` (inclusive). */
|
|
15158
|
+
until: z.number().optional(),
|
|
15159
|
+
limit: z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
|
|
15160
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
15161
|
+
cursor: z.string().optional()
|
|
15162
|
+
});
|
|
15163
|
+
var ListGroupsPageSchema = z.object({
|
|
15164
|
+
groups: z.array(AnalyticsGroupRecordSchema).readonly(),
|
|
15165
|
+
nextCursor: z.string().nullable()
|
|
15166
|
+
});
|
|
15088
15167
|
var KeyEventQueryInput = z.object({
|
|
15089
15168
|
deviceId: z.number(),
|
|
15090
15169
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
@@ -15160,7 +15239,9 @@ var TrackCascadeCountsSchema = z.object({
|
|
|
15160
15239
|
/** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
|
|
15161
15240
|
plates: z.number().int(),
|
|
15162
15241
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
15163
|
-
embeddings: z.number().int()
|
|
15242
|
+
embeddings: z.number().int(),
|
|
15243
|
+
/** Group membership + group rows removed with their last member (best-effort). */
|
|
15244
|
+
groups: z.number().int()
|
|
15164
15245
|
});
|
|
15165
15246
|
/** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
|
|
15166
15247
|
var DiskReconcileCountsSchema = z.object({
|
|
@@ -15332,6 +15413,16 @@ var pipelineAnalyticsCapability = {
|
|
|
15332
15413
|
* are not included (same contract as `listTracks`).
|
|
15333
15414
|
*/
|
|
15334
15415
|
listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
|
|
15416
|
+
/**
|
|
15417
|
+
* Batched co-moving group listing — the Groups feed. Same merge/cursor
|
|
15418
|
+
* contract as {@link listRecentTracks}. A group is a sealed partition of
|
|
15419
|
+
* one session; `getGroup` is the detail with members.
|
|
15420
|
+
*/
|
|
15421
|
+
listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
|
|
15422
|
+
getGroup: method(z.object({
|
|
15423
|
+
deviceId: z.number(),
|
|
15424
|
+
groupId: z.string().min(1)
|
|
15425
|
+
}), AnalyticsGroupDetailSchema.nullable()),
|
|
15335
15426
|
clearTracks: method(z.object({ deviceId: z.number() }), z.void(), {
|
|
15336
15427
|
kind: "mutation",
|
|
15337
15428
|
auth: "admin"
|
|
@@ -15925,6 +16016,33 @@ var NativeCropRefSchema = z.object({
|
|
|
15925
16016
|
h: z.number()
|
|
15926
16017
|
})
|
|
15927
16018
|
});
|
|
16019
|
+
z.object({
|
|
16020
|
+
crop: z.object({
|
|
16021
|
+
left: z.number(),
|
|
16022
|
+
top: z.number(),
|
|
16023
|
+
width: z.number().positive(),
|
|
16024
|
+
height: z.number().positive()
|
|
16025
|
+
}).optional(),
|
|
16026
|
+
content: z.object({
|
|
16027
|
+
width: z.number().int().positive(),
|
|
16028
|
+
height: z.number().int().positive()
|
|
16029
|
+
}),
|
|
16030
|
+
fit: z.enum(["stretch", "contain"]),
|
|
16031
|
+
format: z.enum([
|
|
16032
|
+
"rgb",
|
|
16033
|
+
"gray",
|
|
16034
|
+
"jpeg"
|
|
16035
|
+
])
|
|
16036
|
+
});
|
|
16037
|
+
var FrameRefSchema = z.object({
|
|
16038
|
+
registryId: z.string().min(1),
|
|
16039
|
+
id: z.string().min(1),
|
|
16040
|
+
width: z.number().int().positive(),
|
|
16041
|
+
height: z.number().int().positive(),
|
|
16042
|
+
format: z.enum(["rgb", "gray"]),
|
|
16043
|
+
timestamp: z.number(),
|
|
16044
|
+
capturedAt: z.number().optional()
|
|
16045
|
+
});
|
|
15928
16046
|
var ModelFormatSchema$1 = z.enum([
|
|
15929
16047
|
"onnx",
|
|
15930
16048
|
"coreml",
|
|
@@ -15991,7 +16109,8 @@ var PipelineModelOptionSchema = z.object({
|
|
|
15991
16109
|
sizeMB: z.number()
|
|
15992
16110
|
})),
|
|
15993
16111
|
group: ModelVariantGroupSchema.optional(),
|
|
15994
|
-
legacy: z.boolean().optional()
|
|
16112
|
+
legacy: z.boolean().optional(),
|
|
16113
|
+
provider: ModelProviderIdSchema.optional()
|
|
15995
16114
|
});
|
|
15996
16115
|
var ConfigFieldBridge = z.custom();
|
|
15997
16116
|
var PipelineAddonSchemaSchema = z.object({
|
|
@@ -16246,7 +16365,7 @@ var pipelineExecutorCapability = {
|
|
|
16246
16365
|
* legacy call shape used by existing benchmark code; once all
|
|
16247
16366
|
* callers pass it explicitly we make it required.
|
|
16248
16367
|
*
|
|
16249
|
-
* Exactly one of `frame`, `frameHandle`, `imageBase64`,
|
|
16368
|
+
* Exactly one of `frame`, `frameRef`, `frameHandle`, `imageBase64`,
|
|
16250
16369
|
* `referenceImage` must be provided:
|
|
16251
16370
|
* - `frame`: runtime dispatch path (runner → decoded broker frame).
|
|
16252
16371
|
* Carries the raw buffer, dimensions, and format; the executor
|
|
@@ -16268,6 +16387,12 @@ var pipelineExecutorCapability = {
|
|
|
16268
16387
|
steps: z.array(PipelineStepInputSchema).min(1),
|
|
16269
16388
|
frame: FrameInputSchema.optional(),
|
|
16270
16389
|
/**
|
|
16390
|
+
* Process-local lazy frame. Valid only when caller and provider resolve
|
|
16391
|
+
* in the same execution-group process; split/cross-node callers use
|
|
16392
|
+
* `frame`/`image` inline compatibility instead.
|
|
16393
|
+
*/
|
|
16394
|
+
frameRef: FrameRefSchema.optional(),
|
|
16395
|
+
/**
|
|
16271
16396
|
* CB5 shm passthrough — a `FrameHandle` naming the same ring slot
|
|
16272
16397
|
* the decoded pixels live in. One more member of the one-of
|
|
16273
16398
|
* frame/frameHandle/image/imageBase64/referenceImage group.
|
|
@@ -16617,7 +16742,10 @@ var NativeCropResultSchema = z.object({
|
|
|
16617
16742
|
* Which source served this crop, so a quality-sensitive consumer (the native
|
|
16618
16743
|
* `keyFrame`) can reject a degraded fallback:
|
|
16619
16744
|
* - `native` — cut from the decode worker's retained NATIVE surface (the
|
|
16620
|
-
* quality path).
|
|
16745
|
+
* quality path). A subject-tile serve is also native-resolution and stays
|
|
16746
|
+
* `native` here: the public enum cannot name `tile` without a breaking cap
|
|
16747
|
+
* change. Runner telemetry distinguishes lease vs tile via `source` on the
|
|
16748
|
+
* internal crop result (`nativeHits` vs `tileHits`).
|
|
16621
16749
|
* - `ram-fullframe` — the native surface MISSED but the request was full-frame,
|
|
16622
16750
|
* so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
|
|
16623
16751
|
* the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
|
|
@@ -17108,12 +17236,41 @@ var RunnerLocalLoadSchema = z.object({
|
|
|
17108
17236
|
* legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
|
|
17109
17237
|
* working unchanged when they switch to reading from the runner cap.
|
|
17110
17238
|
*/
|
|
17239
|
+
var FrameLazyCountersSchema = z.object({
|
|
17240
|
+
framesDecoded: z.number(),
|
|
17241
|
+
framesAdmitted: z.number(),
|
|
17242
|
+
framesDroppedPixelFree: z.number(),
|
|
17243
|
+
viewsMaterialized: z.number(),
|
|
17244
|
+
viewsSkipped: z.number(),
|
|
17245
|
+
workerToRunnerBytes: z.number(),
|
|
17246
|
+
runnerToPoolRawBytes: z.number(),
|
|
17247
|
+
runnerToPoolJpegBytes: z.number(),
|
|
17248
|
+
onDemandFullFrameRequests: z.number(),
|
|
17249
|
+
onDemandCropRequests: z.number(),
|
|
17250
|
+
nativeHits: z.number(),
|
|
17251
|
+
nativeMisses: z.number(),
|
|
17252
|
+
tileHits: z.number(),
|
|
17253
|
+
tileMisses: z.number(),
|
|
17254
|
+
fallbackHits: z.number(),
|
|
17255
|
+
fallbackMisses: z.number(),
|
|
17256
|
+
retainedWritesAvoided: z.number(),
|
|
17257
|
+
residentRefs: z.number(),
|
|
17258
|
+
residentBytes: z.number(),
|
|
17259
|
+
releases: z.number(),
|
|
17260
|
+
evictions: z.number(),
|
|
17261
|
+
staleMisses: z.number()
|
|
17262
|
+
});
|
|
17263
|
+
var FrameLazyMetricsSchema = z.object({
|
|
17264
|
+
node: FrameLazyCountersSchema,
|
|
17265
|
+
cameras: z.array(FrameLazyCountersSchema.extend({ deviceId: z.number() }))
|
|
17266
|
+
});
|
|
17111
17267
|
var RunnerLocalMetricsSchema = z.object({
|
|
17112
17268
|
nodeId: z.string(),
|
|
17113
17269
|
activeCameras: z.number(),
|
|
17114
17270
|
throttledCameras: z.number(),
|
|
17115
17271
|
avgInferenceTimeMs: z.number(),
|
|
17116
|
-
queueDepth: z.number()
|
|
17272
|
+
queueDepth: z.number(),
|
|
17273
|
+
frameLazy: FrameLazyMetricsSchema.optional()
|
|
17117
17274
|
});
|
|
17118
17275
|
/**
|
|
17119
17276
|
* Pipeline Runner capability — runtime detection workhorse.
|
|
@@ -23947,6 +24104,17 @@ var NotificationEndpointSchema = z.object({
|
|
|
23947
24104
|
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
23948
24105
|
resolved: z.string().nullable()
|
|
23949
24106
|
});
|
|
24107
|
+
/**
|
|
24108
|
+
* The URLs the SDK / viewer should race for API access. `baseUrls` empty =
|
|
24109
|
+
* AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
|
|
24110
|
+
* currently expands to, so the UI can show the effective set either way.
|
|
24111
|
+
*/
|
|
24112
|
+
var ViewerEndpointsSchema = z.object({
|
|
24113
|
+
/** The operator's explicit race set, or empty for AUTO. */
|
|
24114
|
+
baseUrls: z.array(z.string()).readonly(),
|
|
24115
|
+
/** What the ranking currently resolves to (may be empty if nothing is up). */
|
|
24116
|
+
resolved: z.array(z.string()).readonly()
|
|
24117
|
+
});
|
|
23950
24118
|
var AllowedAddressesSchema = z.object({
|
|
23951
24119
|
/**
|
|
23952
24120
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -23988,13 +24156,13 @@ var localNetworkCapability = {
|
|
|
23988
24156
|
*/
|
|
23989
24157
|
getPreferred: method(z.void(), PreferredSchema),
|
|
23990
24158
|
/**
|
|
23991
|
-
* Ordered candidate base URLs the
|
|
23992
|
-
* Includes LAN
|
|
23993
|
-
*
|
|
23994
|
-
*
|
|
23995
|
-
*
|
|
23996
|
-
*
|
|
23997
|
-
*
|
|
24159
|
+
* Ordered candidate base URLs (the palette the Network tab shows).
|
|
24160
|
+
* Includes LAN IPv4, stable LAN IPv6, the public tunnel, and mesh when
|
|
24161
|
+
* joined. Loopback is off by default. The SDK races the subset from
|
|
24162
|
+
* `getViewerEndpoints`, not this full list — IPv6 stays here because
|
|
24163
|
+
* WebRTC ICE gathers dual-stack regardless of the HTTP race. Honours
|
|
24164
|
+
* `getAllowedAddresses()` when set — addresses outside the allowlist
|
|
24165
|
+
* are dropped (the public tunnel is still included as an escape hatch).
|
|
23998
24166
|
*
|
|
23999
24167
|
* **The port is the hub's, not the caller's** (D62 — a function's fact
|
|
24000
24168
|
* belongs to whoever already owns it). This method used to take a `port`
|
|
@@ -24025,10 +24193,11 @@ var localNetworkCapability = {
|
|
|
24025
24193
|
*/
|
|
24026
24194
|
port: z.number().int().min(1).max(65535).optional(),
|
|
24027
24195
|
/** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
|
|
24028
|
-
* candidate. Default `
|
|
24196
|
+
* candidate. Default `false` — loopback is not a client route. */
|
|
24029
24197
|
includeLoopback: z.boolean().optional(),
|
|
24030
|
-
/** Skip IPv6 entries.
|
|
24031
|
-
*
|
|
24198
|
+
/** Skip IPv6 entries. Default `false` — the palette includes stable
|
|
24199
|
+
* LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
|
|
24200
|
+
* hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
|
|
24032
24201
|
ipv4Only: z.boolean().optional(),
|
|
24033
24202
|
/** Scheme to emit for LAN/loopback URLs. Default `'http'`.
|
|
24034
24203
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
@@ -24057,6 +24226,19 @@ var localNetworkCapability = {
|
|
|
24057
24226
|
*/
|
|
24058
24227
|
setNotificationEndpoint: method(z.object({ baseUrl: z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
|
|
24059
24228
|
/**
|
|
24229
|
+
* The endpoints the SDK / viewer races for API access. Empty `baseUrls`
|
|
24230
|
+
* means AUTO: every LAN IPv4 address plus the public tunnel, never IPv6,
|
|
24231
|
+
* never mesh, never loopback. `resolved` is that set (or the operator's
|
|
24232
|
+
* explicit subset) as it stands right now.
|
|
24233
|
+
*/
|
|
24234
|
+
getViewerEndpoints: method(z.void(), ViewerEndpointsSchema),
|
|
24235
|
+
/**
|
|
24236
|
+
* Replace the viewer race set. Empty `baseUrls` restores AUTO. Stored
|
|
24237
|
+
* verbatim (not indices) so a temporarily-down tunnel is not silently
|
|
24238
|
+
* dropped from the operator's choice.
|
|
24239
|
+
*/
|
|
24240
|
+
setViewerEndpoints: method(z.object({ baseUrls: z.array(z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
|
|
24241
|
+
/**
|
|
24060
24242
|
* Read the operator's allowlist. Empty = "auto" (no filter). Used
|
|
24061
24243
|
* by the admin UI's address selector to seed its checkbox state.
|
|
24062
24244
|
*/
|
|
@@ -25895,7 +26077,12 @@ var PlateInfoSchema = z.object({
|
|
|
25895
26077
|
plateBbox: BoundingBoxSchema.optional(),
|
|
25896
26078
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
25897
26079
|
keyFrameMediaKey: z.string().optional(),
|
|
25898
|
-
base64: z.string().optional()
|
|
26080
|
+
base64: z.string().optional(),
|
|
26081
|
+
/**
|
|
26082
|
+
* Same crop as a data-plane URL. `getPlateByTrack` returns this and
|
|
26083
|
+
* never inlines JPEG; `listPlates` still inlines for the admin-ui.
|
|
26084
|
+
*/
|
|
26085
|
+
cropUrl: z.string().optional()
|
|
25899
26086
|
});
|
|
25900
26087
|
var MediaFileLiteSchema = z.object({
|
|
25901
26088
|
key: z.string(),
|
|
@@ -32591,6 +32778,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
32591
32778
|
addonId: null,
|
|
32592
32779
|
access: "view"
|
|
32593
32780
|
},
|
|
32781
|
+
"localNetwork.getViewerEndpoints": {
|
|
32782
|
+
capName: "local-network",
|
|
32783
|
+
capScope: "system",
|
|
32784
|
+
addonId: null,
|
|
32785
|
+
access: "view"
|
|
32786
|
+
},
|
|
32594
32787
|
"localNetwork.list": {
|
|
32595
32788
|
capName: "local-network",
|
|
32596
32789
|
capScope: "system",
|
|
@@ -32627,6 +32820,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
32627
32820
|
addonId: null,
|
|
32628
32821
|
access: "create"
|
|
32629
32822
|
},
|
|
32823
|
+
"localNetwork.setViewerEndpoints": {
|
|
32824
|
+
capName: "local-network",
|
|
32825
|
+
capScope: "system",
|
|
32826
|
+
addonId: null,
|
|
32827
|
+
access: "create"
|
|
32828
|
+
},
|
|
32630
32829
|
"localNetwork.uploadCertificate": {
|
|
32631
32830
|
capName: "local-network",
|
|
32632
32831
|
capScope: "system",
|
|
@@ -33431,6 +33630,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
33431
33630
|
addonId: null,
|
|
33432
33631
|
access: "view"
|
|
33433
33632
|
},
|
|
33633
|
+
"pipelineAnalytics.getGroup": {
|
|
33634
|
+
capName: "pipeline-analytics",
|
|
33635
|
+
capScope: "device",
|
|
33636
|
+
addonId: null,
|
|
33637
|
+
access: "view"
|
|
33638
|
+
},
|
|
33434
33639
|
"pipelineAnalytics.getKeyEvents": {
|
|
33435
33640
|
capName: "pipeline-analytics",
|
|
33436
33641
|
capScope: "device",
|
|
@@ -33515,6 +33720,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
33515
33720
|
addonId: null,
|
|
33516
33721
|
access: "view"
|
|
33517
33722
|
},
|
|
33723
|
+
"pipelineAnalytics.listGroups": {
|
|
33724
|
+
capName: "pipeline-analytics",
|
|
33725
|
+
capScope: "device",
|
|
33726
|
+
addonId: null,
|
|
33727
|
+
access: "view"
|
|
33728
|
+
},
|
|
33518
33729
|
"pipelineAnalytics.listOpsLog": {
|
|
33519
33730
|
capName: "pipeline-analytics",
|
|
33520
33731
|
capScope: "device",
|
|
@@ -36934,6 +37145,11 @@ Object.freeze({
|
|
|
36934
37145
|
form: "single",
|
|
36935
37146
|
optional: false
|
|
36936
37147
|
}],
|
|
37148
|
+
"pipelineAnalytics.getGroup": [{
|
|
37149
|
+
name: "deviceId",
|
|
37150
|
+
form: "single",
|
|
37151
|
+
optional: false
|
|
37152
|
+
}],
|
|
36937
37153
|
"pipelineAnalytics.getKeyEvents": [{
|
|
36938
37154
|
name: "deviceId",
|
|
36939
37155
|
form: "single",
|
|
@@ -36989,6 +37205,11 @@ Object.freeze({
|
|
|
36989
37205
|
form: "array",
|
|
36990
37206
|
optional: false
|
|
36991
37207
|
}],
|
|
37208
|
+
"pipelineAnalytics.listGroups": [{
|
|
37209
|
+
name: "deviceIds",
|
|
37210
|
+
form: "array",
|
|
37211
|
+
optional: false
|
|
37212
|
+
}],
|
|
36992
37213
|
"pipelineAnalytics.listOpsLog": [{
|
|
36993
37214
|
name: "deviceId",
|
|
36994
37215
|
form: "single",
|
|
@@ -23,13 +23,30 @@ export declare function siblingUrl(mainUrl: string, sibling: string): string;
|
|
|
23
23
|
* agree on the on-disk layout without re-deriving it.
|
|
24
24
|
*/
|
|
25
25
|
export declare function collectModelFiles(entry: ModelCatalogEntry, format: ModelFormat): string[];
|
|
26
|
+
export type DownloadRedirectPolicy = (url: URL, hop: number) => void;
|
|
27
|
+
export interface DownloadFileOptions {
|
|
28
|
+
readonly onProgress?: (downloaded: number, total: number) => void;
|
|
29
|
+
/**
|
|
30
|
+
* When set, redirects are followed manually and THIS policy is applied to
|
|
31
|
+
* the initial URL and every Location hop before the next fetch. Absent ⇒
|
|
32
|
+
* native `redirect: 'follow'` (backward compatible).
|
|
33
|
+
*/
|
|
34
|
+
readonly redirectPolicy?: DownloadRedirectPolicy;
|
|
35
|
+
readonly maxRedirects?: number;
|
|
36
|
+
readonly timeoutMs?: number;
|
|
37
|
+
readonly maxBytes?: number;
|
|
38
|
+
readonly fetchImpl?: typeof fetch;
|
|
39
|
+
}
|
|
26
40
|
/**
|
|
27
41
|
* Download a single file from a URL to a destination path.
|
|
28
|
-
* Uses native fetch() (Node 22+) which handles redirects natively.
|
|
29
42
|
* Streams to disk with optional progress callback.
|
|
30
43
|
* Returns the destination path. Skips download if file already exists.
|
|
44
|
+
*
|
|
45
|
+
* The third argument remains a progress callback for existing callers. Pass
|
|
46
|
+
* an options object to supply a per-hop redirect policy, timeout, or byte cap.
|
|
31
47
|
*/
|
|
32
48
|
export declare function downloadFile(url: string, destPath: string, onProgress?: (downloaded: number, total: number) => void): Promise<string>;
|
|
49
|
+
export declare function downloadFile(url: string, destPath: string, options: DownloadFileOptions): Promise<string>;
|
|
33
50
|
/**
|
|
34
51
|
* Fetch JSON from a URL using native fetch().
|
|
35
52
|
*/
|
|
@@ -50,21 +50,56 @@ function buildHeaders(url) {
|
|
|
50
50
|
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
51
51
|
return headers;
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
54
|
+
function normalizeDownloadOptions(third) {
|
|
55
|
+
if (typeof third === "function") return { onProgress: third };
|
|
56
|
+
return third ?? {};
|
|
57
|
+
}
|
|
58
|
+
function isRedirectStatus(status) {
|
|
59
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
60
|
+
}
|
|
61
|
+
function resolveRedirectUrl(current, location) {
|
|
62
|
+
return new URL(location, current);
|
|
63
|
+
}
|
|
64
|
+
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
60
65
|
if (fs.existsSync(destPath)) return destPath;
|
|
66
|
+
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
67
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
68
|
+
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
61
69
|
fs.mkdirSync(path$1.dirname(destPath), { recursive: true });
|
|
62
70
|
const tmpPath = destPath + ".downloading";
|
|
63
71
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
let current = url;
|
|
73
|
+
const seen = /* @__PURE__ */ new Set();
|
|
74
|
+
let response;
|
|
75
|
+
const manual = opts.redirectPolicy !== void 0;
|
|
76
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
77
|
+
const parsed = new URL(current);
|
|
78
|
+
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
79
|
+
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
80
|
+
seen.add(parsed.href);
|
|
81
|
+
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
82
|
+
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
83
|
+
try {
|
|
84
|
+
response = await fetchImpl(current, {
|
|
85
|
+
redirect: manual ? "manual" : "follow",
|
|
86
|
+
headers: buildHeaders(current),
|
|
87
|
+
...controller ? { signal: controller.signal } : {}
|
|
88
|
+
});
|
|
89
|
+
} finally {
|
|
90
|
+
if (timer) clearTimeout(timer);
|
|
91
|
+
}
|
|
92
|
+
if (manual && isRedirectStatus(response.status)) {
|
|
93
|
+
const location = response.headers.get("location");
|
|
94
|
+
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
95
|
+
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
96
|
+
current = resolveRedirectUrl(current, location).href;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (!response) throw new Error(`No response downloading ${url}`);
|
|
102
|
+
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
68
103
|
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
69
104
|
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
70
105
|
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
@@ -75,9 +110,10 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
75
110
|
for (;;) {
|
|
76
111
|
const { done, value } = await reader.read();
|
|
77
112
|
if (done || !value) break;
|
|
78
|
-
fileStream.write(value);
|
|
79
113
|
downloaded += value.length;
|
|
80
|
-
|
|
114
|
+
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
115
|
+
fileStream.write(value);
|
|
116
|
+
opts.onProgress?.(downloaded, total);
|
|
81
117
|
}
|
|
82
118
|
} finally {
|
|
83
119
|
fileStream.end();
|
|
@@ -51,21 +51,56 @@ function buildHeaders(url) {
|
|
|
51
51
|
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
52
52
|
return headers;
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
55
|
+
function normalizeDownloadOptions(third) {
|
|
56
|
+
if (typeof third === "function") return { onProgress: third };
|
|
57
|
+
return third ?? {};
|
|
58
|
+
}
|
|
59
|
+
function isRedirectStatus(status) {
|
|
60
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
61
|
+
}
|
|
62
|
+
function resolveRedirectUrl(current, location) {
|
|
63
|
+
return new URL(location, current);
|
|
64
|
+
}
|
|
65
|
+
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
61
66
|
if (node_fs.existsSync(destPath)) return destPath;
|
|
67
|
+
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
68
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
69
|
+
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
62
70
|
node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
|
|
63
71
|
const tmpPath = destPath + ".downloading";
|
|
64
72
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
let current = url;
|
|
74
|
+
const seen = /* @__PURE__ */ new Set();
|
|
75
|
+
let response;
|
|
76
|
+
const manual = opts.redirectPolicy !== void 0;
|
|
77
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
78
|
+
const parsed = new URL(current);
|
|
79
|
+
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
80
|
+
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
81
|
+
seen.add(parsed.href);
|
|
82
|
+
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
83
|
+
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
84
|
+
try {
|
|
85
|
+
response = await fetchImpl(current, {
|
|
86
|
+
redirect: manual ? "manual" : "follow",
|
|
87
|
+
headers: buildHeaders(current),
|
|
88
|
+
...controller ? { signal: controller.signal } : {}
|
|
89
|
+
});
|
|
90
|
+
} finally {
|
|
91
|
+
if (timer) clearTimeout(timer);
|
|
92
|
+
}
|
|
93
|
+
if (manual && isRedirectStatus(response.status)) {
|
|
94
|
+
const location = response.headers.get("location");
|
|
95
|
+
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
96
|
+
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
97
|
+
current = resolveRedirectUrl(current, location).href;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
if (!response) throw new Error(`No response downloading ${url}`);
|
|
103
|
+
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
69
104
|
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
70
105
|
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
71
106
|
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
@@ -76,9 +111,10 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
76
111
|
for (;;) {
|
|
77
112
|
const { done, value } = await reader.read();
|
|
78
113
|
if (done || !value) break;
|
|
79
|
-
fileStream.write(value);
|
|
80
114
|
downloaded += value.length;
|
|
81
|
-
|
|
115
|
+
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
116
|
+
fileStream.write(value);
|
|
117
|
+
opts.onProgress?.(downloaded, total);
|
|
82
118
|
}
|
|
83
119
|
} finally {
|
|
84
120
|
fileStream.end();
|