@camstack/addon-provider-onvif 1.1.21 → 1.1.23

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.
Files changed (3) hide show
  1. package/dist/addon.js +498 -94
  2. package/dist/addon.mjs +498 -94
  3. package/package.json +4 -1
package/dist/addon.js CHANGED
@@ -4631,7 +4631,7 @@ function _instanceof(cls, params = {}) {
4631
4631
  return inst;
4632
4632
  }
4633
4633
  //#endregion
4634
- //#region ../types/dist/sleep-Cc14_yxc.mjs
4634
+ //#region ../types/dist/sleep-BC9Yqte7.mjs
4635
4635
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4636
4636
  EventCategory["SystemBoot"] = "system.boot";
4637
4637
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5352,10 +5352,6 @@ function hydrateField(field, values) {
5352
5352
  };
5353
5353
  }
5354
5354
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5355
- if (field.type === "password") return {
5356
- ...field,
5357
- value: ""
5358
- };
5359
5355
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5360
5356
  return {
5361
5357
  ...field,
@@ -6739,6 +6735,21 @@ function method(input, output, options) {
6739
6735
  timeoutMs: options?.timeoutMs
6740
6736
  };
6741
6737
  }
6738
+ /**
6739
+ * A wrapper/system-only method: served exclusively by the cap's system-level
6740
+ * provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
6741
+ * driver natives don't stub out a wrapper concern (e.g. a cross-device cache
6742
+ * overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
6743
+ */
6744
+ function systemMethod(input, output, options) {
6745
+ return {
6746
+ ...method(input, output, options),
6747
+ systemOnly: true
6748
+ };
6749
+ }
6750
+ var StaticDirOutputSchema$1 = object({ staticDir: string() });
6751
+ var VersionOutputSchema$1 = object({ version: string() });
6752
+ method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6742
6753
  var StaticDirOutputSchema = object({ staticDir: string() });
6743
6754
  var VersionOutputSchema = object({ version: string() });
6744
6755
  method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
@@ -10481,7 +10492,7 @@ var BoundingBoxSchema = object({
10481
10492
  w: number(),
10482
10493
  h: number()
10483
10494
  });
10484
- var SpatialDetectionSchema = object({
10495
+ object({
10485
10496
  class: string(),
10486
10497
  originalClass: string(),
10487
10498
  score: number(),
@@ -10656,6 +10667,7 @@ var PipelineAddonSchemaSchema = object({
10656
10667
  defaultModelId: string(),
10657
10668
  defaultModelIdByFormat: record(string(), string()).optional(),
10658
10669
  enabledByDefault: boolean().optional(),
10670
+ backfillIntoExistingOverrides: boolean().optional(),
10659
10671
  defaultConfidence: number(),
10660
10672
  group: string().optional(),
10661
10673
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -10672,11 +10684,6 @@ var PipelineSchemaSchema = object({
10672
10684
  selectedEngine: PipelineEngineChoiceSchema,
10673
10685
  slots: array(PipelineSlotSchemaSchema).readonly()
10674
10686
  });
10675
- var DetectorOutputSchema = object({
10676
- detections: array(SpatialDetectionSchema).readonly(),
10677
- inferenceMs: number(),
10678
- modelId: string()
10679
- });
10680
10687
  var EngineProvisioningSchema = object({
10681
10688
  runtimeId: _enum([
10682
10689
  "onnx",
@@ -10801,7 +10808,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10801
10808
  auth: "admin"
10802
10809
  }), method(object({ nodeId: string() }), object({
10803
10810
  success: literal(true),
10804
- regeneratedModelId: string().nullable()
10811
+ clearedDevices: number()
10805
10812
  }), {
10806
10813
  kind: "mutation",
10807
10814
  auth: "admin"
@@ -10822,10 +10829,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10822
10829
  modelId: string(),
10823
10830
  format: ModelFormatSchema$1
10824
10831
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
10825
- addonId: string(),
10826
- frame: FrameInputSchema,
10827
- config: record(string(), unknown()).optional()
10828
- }), DetectorOutputSchema), method(object({
10829
10832
  engine: PipelineEngineChoiceSchema.optional(),
10830
10833
  steps: array(PipelineStepInputSchema).min(1),
10831
10834
  frame: FrameInputSchema.optional(),
@@ -10971,6 +10974,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(ZoneSchema).read
10971
10974
  auth: "admin"
10972
10975
  }), object({ zones: array(ZoneSchema).readonly() });
10973
10976
  /**
10977
+ * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
10978
+ * decode worker resolves it against the RETAINED native frame's real pixel dims,
10979
+ * so the caller supplies only the detection-res bbox divided by the detection
10980
+ * dims — no native resolution to plumb.
10981
+ */
10982
+ var NativeCropBboxSchema = object({
10983
+ x: number(),
10984
+ y: number(),
10985
+ w: number(),
10986
+ h: number()
10987
+ });
10988
+ /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
10989
+ var NativeCropResultSchema = object({
10990
+ /** Packed rgb (24-bit) pixels of the crop. */
10991
+ bytes: _instanceof(Uint8Array),
10992
+ width: number().int().positive(),
10993
+ height: number().int().positive()
10994
+ });
10995
+ /**
10974
10996
  * Per-camera tunable ranges + defaults. Single source of truth used
10975
10997
  * by both the Zod data schema (validation + default fallback) and
10976
10998
  * the device settings UI (slider min/max/step). Touch one place and
@@ -11226,7 +11248,11 @@ var RunnerLocalMetricsSchema = object({
11226
11248
  avgInferenceTimeMs: number(),
11227
11249
  queueDepth: number()
11228
11250
  });
11229
- 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());
11251
+ 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({
11252
+ handle: FrameHandleSchema,
11253
+ bbox: NativeCropBboxSchema,
11254
+ maxWidth: number().int().positive().optional()
11255
+ }), NativeCropResultSchema.nullable());
11230
11256
  object({
11231
11257
  detected: boolean(),
11232
11258
  /** Ms epoch of the last detected-true observation. Null if never detected. */
@@ -12814,7 +12840,9 @@ var AddonPageDeclarationSchema$1 = object({
12814
12840
  icon: string(),
12815
12841
  path: string(),
12816
12842
  remoteName: string(),
12817
- bundle: string()
12843
+ bundle: string(),
12844
+ section: string().optional(),
12845
+ sectionLabel: string().optional()
12818
12846
  });
12819
12847
  var AddonPageInfoSchema = object({
12820
12848
  addonId: string(),
@@ -12854,7 +12882,18 @@ var AddonPageDeclarationSchema = object({
12854
12882
  * the static-file route can compute an mtime-based cache-buster URL
12855
12883
  * without a separate filesystem stat.
12856
12884
  */
12857
- bundle: string()
12885
+ bundle: string(),
12886
+ /**
12887
+ * Sidebar section this page docks into. Well-known ids: `'detection'`,
12888
+ * `'cluster'`, `'administration'` — the page renders inside that group.
12889
+ * Any OTHER string creates (or joins) a custom section rendered after
12890
+ * the built-in groups; its label comes from `sectionLabel` (first
12891
+ * declaration wins), falling back to the id. Absent → the legacy
12892
+ * "Addon Pages" group.
12893
+ */
12894
+ section: string().optional(),
12895
+ /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
12896
+ sectionLabel: string().optional()
12858
12897
  });
12859
12898
  method(_void(), array(AddonPageDeclarationSchema).readonly());
12860
12899
  var AddonHttpRouteSchema = object({
@@ -13070,6 +13109,17 @@ var WidgetMetadataSchema = object({
13070
13109
  deviceContext: boolean().default(false),
13071
13110
  integrationContext: boolean().default(false)
13072
13111
  }),
13112
+ /**
13113
+ * Loadable BEFORE authentication. The normal widget registry listing
13114
+ * (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
13115
+ * (the login page) cannot discover a widget through it. A widget that
13116
+ * declares `preAuth: true` marks itself as safe to mount on a pre-auth
13117
+ * screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
13118
+ * login-method contribution channel (see `login-method.cap.ts`) rather
13119
+ * than the authenticated registry, and its bundle is served by the
13120
+ * public `/api/addon-widgets/:addonId/*` static route. Defaults false.
13121
+ */
13122
+ preAuth: boolean().optional().default(false),
13073
13123
  /** Dashboard placement HINTS (operator can override per instance). */
13074
13124
  defaultSize: WidgetSizeEnum.default("md"),
13075
13125
  allowedSizes: array(WidgetSizeEnum).readonly().default([
@@ -13371,6 +13421,66 @@ method(object({
13371
13421
  password: string()
13372
13422
  }), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
13373
13423
  /**
13424
+ * `login-method` — collection cap through which auth addons contribute
13425
+ * their pre-auth login surfaces to the login page. This is the SINGLE,
13426
+ * generic mechanism that supersedes the dead `auth.listProviders` reader:
13427
+ * every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
13428
+ * `login-method` provider and the PUBLIC `auth.listLoginMethods`
13429
+ * procedure aggregates them for the unauthenticated login page.
13430
+ *
13431
+ * A contribution is a discriminated union on `kind`:
13432
+ *
13433
+ * - `redirect` — a declarative button. The login page renders a generic
13434
+ * button that navigates to `startUrl` (an addon-owned HTTP route).
13435
+ * Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
13436
+ * ZERO shell-side JS. A future SSO addon plugs in the same way — the
13437
+ * login page needs NO change.
13438
+ *
13439
+ * - `widget` — a Module-Federation widget the login page mounts (via
13440
+ * `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
13441
+ * login ceremony, which must run `@simplewebauthn/browser` INSIDE the
13442
+ * addon bundle. The referenced widget also declares `preAuth: true` in
13443
+ * its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
13444
+ * stamps a public `bundleUrl` from `addonId` + `bundle`.
13445
+ *
13446
+ * Every contribution carries a `stage`:
13447
+ * - `primary` — shown on the first credentials screen (OIDC /
13448
+ * magic-link buttons; a future usernameless passkey).
13449
+ * - `second-factor` — shown AFTER the password leg, gated on the
13450
+ * returned `factors` (passkey-as-2FA today).
13451
+ *
13452
+ * `mount: skip` — the cap is read server-side by the core auth router
13453
+ * (`registry.getCollection('login-method')`), never mounted as its own
13454
+ * tRPC router.
13455
+ */
13456
+ /** When a login method renders in the two-phase login flow. */
13457
+ var LoginStageEnum = _enum(["primary", "second-factor"]);
13458
+ /** One login-method contribution — redirect button OR pre-auth widget. */
13459
+ var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
13460
+ kind: literal("redirect"),
13461
+ /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
13462
+ id: string(),
13463
+ /** Operator-facing button label. */
13464
+ label: string(),
13465
+ /** lucide-react icon name. */
13466
+ icon: string().optional(),
13467
+ /** Addon-owned HTTP route the button navigates to (GET). */
13468
+ startUrl: string(),
13469
+ stage: LoginStageEnum
13470
+ }), object({
13471
+ kind: literal("widget"),
13472
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
13473
+ id: string(),
13474
+ /** Owning addon id — drives the public bundle URL + the MF namespace. */
13475
+ addonId: string(),
13476
+ /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
13477
+ bundle: string(),
13478
+ /** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
13479
+ remote: WidgetRemoteSchema,
13480
+ stage: LoginStageEnum
13481
+ })]);
13482
+ method(_void(), array(LoginMethodContributionSchema).readonly());
13483
+ /**
13374
13484
  * Orchestrator-side destination metadata. The orchestrator computes
13375
13485
  * `id = <addonId>:<subId>` from its provider lookup so consumers
13376
13486
  * (admin UI, restore flow) see one canonical key.
@@ -15474,7 +15584,17 @@ var TrackSchema = object({
15474
15584
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
15475
15585
  totalDistance: number(),
15476
15586
  state: TrackStateSchema,
15477
- active: boolean()
15587
+ active: boolean(),
15588
+ /** Deterministic key-event importance score in [0,1] (server-computed at
15589
+ * track expiry, recomputed on late label). Absent on legacy rows written
15590
+ * before scoring shipped — consumers degrade to absence / compute-on-read. */
15591
+ importance: number().optional(),
15592
+ /** Id of the track's highest-confidence ObjectEvent (its representative
15593
+ * "best" frame). Absent when the track produced no object events. */
15594
+ bestEventId: string().optional(),
15595
+ /** Tag of the importance sub-signal that dominated the score
15596
+ * (identity|dwell|proximity|class|confidence|travel|zone). */
15597
+ importanceReason: string().optional()
15478
15598
  });
15479
15599
  var BaseEventFields = {
15480
15600
  id: string(),
@@ -15539,8 +15659,18 @@ var ObjectEventSchema = object({
15539
15659
  frameHeight: number().optional(),
15540
15660
  /** MediaStore key for the crop attached to this event (if any). */
15541
15661
  mediaKey: string().optional(),
15662
+ /** Design B: MediaStore key of the track's native-resolution key frame (the
15663
+ * best-detection full frame). Resolve via the event-media data-plane
15664
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
15665
+ * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
15666
+ * sources — consumers fall back to `mediaKey` (the tight crop). */
15667
+ keyFrameMediaKey: string().optional(),
15542
15668
  /** Populated by B5 (recording playback URL for this event). */
15543
- mediaUrl: string().optional()
15669
+ mediaUrl: string().optional(),
15670
+ /** The parent track's key-event importance [0,1], propagated to every object
15671
+ * event of the track (so an event row can be sorted by importance without a
15672
+ * track join). Absent on legacy rows / before the track was scored. */
15673
+ importance: number().optional()
15544
15674
  });
15545
15675
  var AudioEventSchema = object({
15546
15676
  ...BaseEventFields,
@@ -15564,7 +15694,8 @@ var MediaFileKindEnum = _enum([
15564
15694
  "fullFrame",
15565
15695
  "fullFrameBoxed",
15566
15696
  "faceCrop",
15567
- "plateCrop"
15697
+ "plateCrop",
15698
+ "keyFrame"
15568
15699
  ]);
15569
15700
  var MediaFileSchema = object({
15570
15701
  key: string(),
@@ -15585,6 +15716,32 @@ var DeviceEventQueryInput = object({
15585
15716
  projection: _enum(["full", "slim"]).optional()
15586
15717
  });
15587
15718
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
15719
+ var KeyEventQueryInput = object({
15720
+ deviceId: number(),
15721
+ /** Window lower bound (track firstSeen ≥ since). */
15722
+ since: number(),
15723
+ /** Window upper bound (track firstSeen ≤ until). */
15724
+ until: number(),
15725
+ limit: number().int().min(1).max(200).default(50),
15726
+ /** Drop tracks scoring below this importance. */
15727
+ minImportance: number().min(0).max(1).optional(),
15728
+ /** Restrict to a single class (e.g. 'person'). */
15729
+ classFilter: string().optional()
15730
+ });
15731
+ var KeyEventSchema = object({
15732
+ /** The representative event id (the track's best ObjectEvent, else its trackId). */
15733
+ id: string(),
15734
+ trackId: string(),
15735
+ /** Track start time (firstSeen). */
15736
+ timestamp: number(),
15737
+ className: string(),
15738
+ label: string().optional(),
15739
+ importance: number(),
15740
+ /** Highest-confidence ObjectEvent id for the track (empty when none). */
15741
+ bestEventId: string(),
15742
+ /** Track lifetime in ms (lastSeen - firstSeen). */
15743
+ windowMs: number().optional()
15744
+ });
15588
15745
  var TrackedDetectionSchema = object({
15589
15746
  trackId: string(),
15590
15747
  className: string(),
@@ -15614,7 +15771,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15614
15771
  }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
15615
15772
  kind: "mutation",
15616
15773
  auth: "admin"
15617
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
15774
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
15618
15775
  deviceId: number(),
15619
15776
  since: number(),
15620
15777
  until: number(),
@@ -15688,7 +15845,12 @@ var AgentPipelineSettingsSchema = object({
15688
15845
  detectWeight: number().positive().optional(),
15689
15846
  /** Node is eligible to run the detection pipeline (decode + inference). */
15690
15847
  detect: boolean().optional(),
15691
- /** Node is eligible to host decoder sessions. */
15848
+ /**
15849
+ * DEPRECATED AND IGNORED. Decode is always co-located with its frame
15850
+ * consumer, so decode eligibility IS detect eligibility. Kept optional in
15851
+ * the schema ONLY so persisted stores written before the removal still
15852
+ * parse — no code reads it and no write path emits it.
15853
+ */
15692
15854
  decode: boolean().optional(),
15693
15855
  /** Node is eligible to run audio-analyzer sessions. */
15694
15856
  audio: boolean().optional(),
@@ -15749,25 +15911,6 @@ var PipelineAssignmentSchema = object({
15749
15911
  assignedAt: number()
15750
15912
  });
15751
15913
  /**
15752
- * Decoder placement record. Symmetric to `PipelineAssignmentSchema` but for
15753
- * the decoder-node placement domain (`balanceDecoder` decision: manual pin
15754
- * → co-located with pipeline → capacity).
15755
- */
15756
- var DecoderAssignmentSchema = object({
15757
- deviceId: number(),
15758
- /** Moleculer node id of the decoder provider currently responsible for this camera. */
15759
- decoderNodeId: string(),
15760
- /** True when the assignment was set manually via `assignDecoder`, false when chosen by the balancer. */
15761
- pinned: boolean(),
15762
- /** Why this assignment was made — useful for debugging the decoder balancer. */
15763
- reason: _enum([
15764
- "manual",
15765
- "co-located",
15766
- "capacity",
15767
- "hardware-affinity"
15768
- ])
15769
- });
15770
- /**
15771
15914
  * Per-agent load summary surfaced to the load balancer + dashboards.
15772
15915
  * Aggregated from each runner's `getLocalLoad` cap call.
15773
15916
  */
@@ -15973,15 +16116,6 @@ method(object({
15973
16116
  }), method(_void(), IngestOwnerSchema), method(object({
15974
16117
  deviceId: number(),
15975
16118
  nodeId: string()
15976
- }), _void(), {
15977
- kind: "mutation",
15978
- auth: "admin"
15979
- }), method(object({ deviceId: number() }), _void(), {
15980
- kind: "mutation",
15981
- auth: "admin"
15982
- }), method(_void(), array(DecoderAssignmentSchema).readonly()), method(object({
15983
- deviceId: number(),
15984
- nodeId: string()
15985
16119
  }), object({ success: literal(true) }), {
15986
16120
  kind: "mutation",
15987
16121
  auth: "admin"
@@ -16000,10 +16134,7 @@ method(object({
16000
16134
  nodeId: string(),
16001
16135
  pinned: boolean(),
16002
16136
  assignedAt: number()
16003
- }))), method(object({
16004
- deviceId: number(),
16005
- pipelineNodeId: string().optional()
16006
- }), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
16137
+ }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
16007
16138
  nodeId: string(),
16008
16139
  settings: AgentPipelineSettingsSchema
16009
16140
  })).readonly()), method(object({
@@ -16033,7 +16164,6 @@ method(object({
16033
16164
  }), method(object({
16034
16165
  agentNodeId: string(),
16035
16166
  detect: boolean().nullable().optional(),
16036
- decode: boolean().nullable().optional(),
16037
16167
  audio: boolean().nullable().optional(),
16038
16168
  ingest: boolean().nullable().optional()
16039
16169
  }), object({ success: literal(true) }), {
@@ -16045,6 +16175,15 @@ method(object({
16045
16175
  }), object({ success: literal(true) }), {
16046
16176
  kind: "mutation",
16047
16177
  auth: "admin"
16178
+ }), method(object({ agentNodeId: string() }), object({
16179
+ success: literal(true),
16180
+ /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
16181
+ effectiveModelId: string().nullable(),
16182
+ /** Number of cameras whose node-scoped overrides were cleared. */
16183
+ clearedCameraOverrides: number()
16184
+ }), {
16185
+ kind: "mutation",
16186
+ auth: "admin"
16048
16187
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
16049
16188
  deviceId: number(),
16050
16189
  addonId: string(),
@@ -16090,6 +16229,131 @@ method(object({
16090
16229
  auth: "admin"
16091
16230
  });
16092
16231
  /**
16232
+ * server-management — per-NODE singleton capability for a node's ROOT
16233
+ * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
16234
+ * agents).
16235
+ *
16236
+ * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
16237
+ * on agents) carries the whole software stack in its npm dep tree, so ONE
16238
+ * version describes the node. Updates install into
16239
+ * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
16240
+ * starter (probation boot + auto-rollback to N-1).
16241
+ *
16242
+ * Providers:
16243
+ * - HUB: `ServerUpdateService` behind the `server-provided` mount
16244
+ * (`buildServerProviders` in trpc.router.ts) — the default target for
16245
+ * unpinned calls.
16246
+ * - AGENT: `AgentUpdateService` registered by the agent bootstrap under
16247
+ * the synthetic `agent-runtime` addonId and declared in the agent's
16248
+ * `$hub.registerNode` manifest.
16249
+ *
16250
+ * Node routing: singleton caps get the codegen/runtime-builder `nodeId`
16251
+ * injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
16252
+ * SDK) routes the call to that node's provider via the standard remote
16253
+ * proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
16254
+ * in-process provider lookup). No `nodeId` → the hub's own provider.
16255
+ *
16256
+ * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
16257
+ */
16258
+ /**
16259
+ * Where the running hub's code was loaded from:
16260
+ * - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
16261
+ * plain resolution and runtime updates are refused.
16262
+ * - `baked` — the immutable image seed closure (no data-dir root active).
16263
+ * - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
16264
+ */
16265
+ var ServerBootModeSchema = _enum([
16266
+ "workspace",
16267
+ "baked",
16268
+ "data-root"
16269
+ ]);
16270
+ /**
16271
+ * Update lifecycle state:
16272
+ * - `idle` / `checking` / `staging` — steady / in-flight registry work.
16273
+ * - `pending-restart` — a version is staged and the node has NOT yet
16274
+ * restarted onto it (still running the OLD version).
16275
+ * - `awaiting-confirmation` — the node HAS restarted onto the staged version
16276
+ * (it is the active probation boot) and is waiting to confirm boot-health.
16277
+ * Apply/rollback are refused in this state and the node must NOT be
16278
+ * manually restarted, or the probation boot auto-rolls-back.
16279
+ */
16280
+ var ServerUpdateStateSchema = _enum([
16281
+ "idle",
16282
+ "checking",
16283
+ "staging",
16284
+ "pending-restart",
16285
+ "awaiting-confirmation"
16286
+ ]);
16287
+ var ServerRollbackInfoSchema = object({
16288
+ /** The version that failed (or was manually rolled back). */
16289
+ fromVersion: string(),
16290
+ /** The version rolled back to; null = the baked seed. */
16291
+ toVersion: string().nullable(),
16292
+ atMs: number(),
16293
+ reason: string()
16294
+ });
16295
+ var ServerPackageStatusSchema = object({
16296
+ /** Root package name (`@camstack/server` on the hub). */
16297
+ packageName: string(),
16298
+ /** Version of the code the running process ACTUALLY loaded. */
16299
+ runningVersion: string().nullable(),
16300
+ /** Node.js runtime version the node's process runs on (`process.versions.node`). */
16301
+ nodeRuntimeVersion: string().nullable(),
16302
+ /** Active data-dir root version; null when booted from seed/workspace. */
16303
+ activeVersion: string().nullable(),
16304
+ /** N-1 version kept for rollback; null when no previous version exists. */
16305
+ previousVersion: string().nullable(),
16306
+ /** Version of the immutable baked seed closure (image fallback). */
16307
+ seedVersion: string().nullable(),
16308
+ /** Latest registry version from the most recent check (null = never checked). */
16309
+ latestVersion: string().nullable(),
16310
+ updateAvailable: boolean(),
16311
+ bootMode: ServerBootModeSchema,
16312
+ updateState: ServerUpdateStateSchema,
16313
+ /** Version staged + awaiting its probation boot, when one is pending. */
16314
+ pendingVersion: string().nullable(),
16315
+ /** Set when the last freshly-activated version failed its boot health-check. */
16316
+ rolledBack: ServerRollbackInfoSchema.nullable(),
16317
+ /**
16318
+ * True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
16319
+ * hub is running from the baked seed (or workspace) while installed data-dir
16320
+ * versions are being IGNORED. Surfaced as a warning in the UI.
16321
+ */
16322
+ stateFileCorrupt: boolean(),
16323
+ lastCheckedAtMs: number().nullable()
16324
+ });
16325
+ var ServerUpdateCheckResultSchema = object({
16326
+ packageName: string(),
16327
+ runningVersion: string().nullable(),
16328
+ latestVersion: string().nullable(),
16329
+ updateAvailable: boolean(),
16330
+ checkedAtMs: number(),
16331
+ /** Non-null when the registry lookup failed (offline, bad registry, …). */
16332
+ error: string().nullable()
16333
+ });
16334
+ var ServerUpdateActionResultSchema = object({
16335
+ accepted: boolean(),
16336
+ targetVersion: string().nullable(),
16337
+ /** True when a graceful restart was scheduled to apply the change. */
16338
+ restarting: boolean(),
16339
+ message: string()
16340
+ });
16341
+ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
16342
+ kind: "mutation",
16343
+ auth: "admin"
16344
+ }), method(object({
16345
+ /** Explicit target version; omitted = latest from the registry. */
16346
+ version: string().optional() }), ServerUpdateActionResultSchema, {
16347
+ kind: "mutation",
16348
+ auth: "admin"
16349
+ }), method(_void(), ServerUpdateActionResultSchema, {
16350
+ kind: "mutation",
16351
+ auth: "admin"
16352
+ }), method(_void(), ServerUpdateActionResultSchema, {
16353
+ kind: "mutation",
16354
+ auth: "admin"
16355
+ });
16356
+ /**
16093
16357
  * Query filter for settings-store collections.
16094
16358
  */
16095
16359
  var QueryFilterSchema = object({
@@ -16311,7 +16575,20 @@ var snapshotCapability = {
16311
16575
  invalidateCache: method(object({ deviceId: number() }), _void(), {
16312
16576
  kind: "mutation",
16313
16577
  auth: "admin"
16314
- })
16578
+ }),
16579
+ /**
16580
+ * Cache-only batch overview — answers from the wrapper's in-memory cache in
16581
+ * O(n) and NEVER triggers a capture. Lets a grid skip requesting images for
16582
+ * devices that never produced a frame, and gives it an ETag per device for
16583
+ * conditional (304-able) image fetches. `lastCapturedAt`/`cacheAgeMs`/`etag`
16584
+ * are null for a device with no cached frame.
16585
+ */
16586
+ getSnapshotOverview: systemMethod(object({ deviceIds: array(number()).min(1).max(200) }), array(object({
16587
+ deviceId: number(),
16588
+ lastCapturedAt: number().nullable(),
16589
+ cacheAgeMs: number().nullable(),
16590
+ etag: string().nullable()
16591
+ })))
16315
16592
  },
16316
16593
  status: {
16317
16594
  schema: SnapshotStatusSchema,
@@ -16568,10 +16845,32 @@ method(_void(), array(TurnServerSchema).readonly());
16568
16845
  * b. `finishAuthentication({userId, response})` → server verifies
16569
16846
  * the assertion, bumps the credential counter, returns ok.
16570
16847
  *
16848
+ * 2b. Usernameless (discoverable-credential) authentication — the
16849
+ * passkey IS the primary factor, no password leg:
16850
+ * a. `beginDiscoverableAuthentication({})` → assertion options with
16851
+ * EMPTY `allowCredentials` (the browser offers every resident
16852
+ * passkey it holds for this RP) + `userVerification: 'required'`
16853
+ * (the passkey replaces both factors, so UV is mandatory).
16854
+ * The challenge is stored server-side, NOT bound to any user.
16855
+ * b. `finishDiscoverableAuthentication({response})` → the provider
16856
+ * resolves the credential by the response's credential id,
16857
+ * verifies the assertion against the stored challenge + that
16858
+ * credential's public key/counter, and returns the OWNING
16859
+ * `userId` — the caller (core auth router) mints the session.
16860
+ *
16571
16861
  * 3. Management:
16572
16862
  * - `listPasskeys({userId})` — enumerate user's enrolled credentials.
16573
16863
  * - `removePasskey({userId, credentialId})` — revoke one credential.
16574
16864
  *
16865
+ * 4. Second-factor preference (opt-in, default OFF):
16866
+ * Enrolling a passkey only enables passkey-FIRST sign-in. It is
16867
+ * demanded as a second factor after a password login ONLY when the
16868
+ * user explicitly opts in via `setSecondFactorPreference`.
16869
+ * - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
16870
+ * row ⇒ `enabled: false`).
16871
+ * - `setSecondFactorPreference({userId, enabled})` — persisted by
16872
+ * the providing addon beside its credentials.
16873
+ *
16575
16874
  * Challenges are short-lived (5 min, in-memory). The cap is internal —
16576
16875
  * the admin-ui composes the begin/finish round-trip and never exposes
16577
16876
  * the cap to non-admins.
@@ -16614,6 +16913,17 @@ method(object({
16614
16913
  }), object({ verified: boolean() }), {
16615
16914
  kind: "mutation",
16616
16915
  access: "view"
16916
+ }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
16917
+ kind: "mutation",
16918
+ access: "view"
16919
+ }), method(object({
16920
+ /** AuthenticationResponseJSON from the browser. */
16921
+ response: record(string(), unknown()) }), object({
16922
+ verified: boolean(),
16923
+ userId: string().nullable()
16924
+ }), {
16925
+ kind: "mutation",
16926
+ access: "view"
16617
16927
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
16618
16928
  userId: string(),
16619
16929
  credentialId: string()
@@ -16621,6 +16931,13 @@ method(object({
16621
16931
  kind: "mutation",
16622
16932
  auth: "admin",
16623
16933
  access: "delete"
16934
+ }), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
16935
+ userId: string(),
16936
+ enabled: boolean()
16937
+ }), object({ success: literal(true) }), {
16938
+ kind: "mutation",
16939
+ auth: "admin",
16940
+ access: "create"
16624
16941
  });
16625
16942
  /**
16626
16943
  * `videoclips` — the unified, navigable-clip surface for a camera.
@@ -17422,7 +17739,17 @@ var FaceInfoSchema = object({
17422
17739
  recognizedIdentityId: string().optional(),
17423
17740
  identityName: string().optional(),
17424
17741
  assigned: boolean(),
17425
- base64: string().optional()
17742
+ base64: string().optional(),
17743
+ /** Design B: the face bbox (pixel space) on the key frame — lets a detail
17744
+ * view draw the box over the native `keyFrameMediaKey` frame. Absent on
17745
+ * legacy rows written before design B. */
17746
+ faceBbox: BoundingBoxSchema.optional(),
17747
+ /** Design B: MediaStore key of the track's native-resolution key frame.
17748
+ * Fetch the native JPEG via the event-media data-plane
17749
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
17750
+ * track produced no key frame (e.g. native/onboard source) — the UI falls
17751
+ * back to the inline `base64` face crop. */
17752
+ keyFrameMediaKey: string().optional()
17426
17753
  });
17427
17754
  var FaceFilterEnum = _enum([
17428
17755
  "unassigned",
@@ -18119,6 +18446,16 @@ var TopologyCategorySchema = object({
18119
18446
  healthy: number(),
18120
18447
  addons: array(TopologyCategoryAddonSchema).readonly()
18121
18448
  });
18449
+ /**
18450
+ * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
18451
+ * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
18452
+ * version visibility for the Server management surface. Nullable: offline
18453
+ * rows and pre-phase-2 nodes report none.
18454
+ */
18455
+ var TopologyRootPackageSchema = object({
18456
+ name: string(),
18457
+ version: string()
18458
+ });
18122
18459
  var TopologyNodeSchema = object({
18123
18460
  id: string(),
18124
18461
  name: string(),
@@ -18142,7 +18479,8 @@ var TopologyNodeSchema = object({
18142
18479
  status: string()
18143
18480
  })).readonly(),
18144
18481
  processes: array(TopologyProcessSchema).readonly(),
18145
- categories: array(TopologyCategorySchema).readonly()
18482
+ categories: array(TopologyCategorySchema).readonly(),
18483
+ rootPackage: TopologyRootPackageSchema.nullable()
18146
18484
  });
18147
18485
  var CapUsageEdgeSchema = object({
18148
18486
  callerAddonId: string(),
@@ -20984,6 +21322,12 @@ Object.freeze({
20984
21322
  addonId: null,
20985
21323
  access: "create"
20986
21324
  },
21325
+ "loginMethod.getLoginMethods": {
21326
+ capName: "login-method",
21327
+ capScope: "system",
21328
+ addonId: null,
21329
+ access: "view"
21330
+ },
20987
21331
  "mediaPlayer.next": {
20988
21332
  capName: "media-player",
20989
21333
  capScope: "device",
@@ -21566,6 +21910,12 @@ Object.freeze({
21566
21910
  addonId: null,
21567
21911
  access: "view"
21568
21912
  },
21913
+ "pipelineAnalytics.getKeyEvents": {
21914
+ capName: "pipeline-analytics",
21915
+ capScope: "device",
21916
+ addonId: null,
21917
+ access: "view"
21918
+ },
21569
21919
  "pipelineAnalytics.getMotionEvents": {
21570
21920
  capName: "pipeline-analytics",
21571
21921
  capScope: "device",
@@ -21614,23 +21964,23 @@ Object.freeze({
21614
21964
  addonId: null,
21615
21965
  access: "create"
21616
21966
  },
21617
- "pipelineExecutor.deleteModel": {
21967
+ "pipelineExecutor.clearDeviceOverrides": {
21618
21968
  capName: "pipeline-executor",
21619
21969
  capScope: "system",
21620
21970
  addonId: null,
21621
21971
  access: "delete"
21622
21972
  },
21623
- "pipelineExecutor.deleteTemplate": {
21973
+ "pipelineExecutor.deleteModel": {
21624
21974
  capName: "pipeline-executor",
21625
21975
  capScope: "system",
21626
21976
  addonId: null,
21627
21977
  access: "delete"
21628
21978
  },
21629
- "pipelineExecutor.detect": {
21979
+ "pipelineExecutor.deleteTemplate": {
21630
21980
  capName: "pipeline-executor",
21631
21981
  capScope: "system",
21632
21982
  addonId: null,
21633
- access: "view"
21983
+ access: "delete"
21634
21984
  },
21635
21985
  "pipelineExecutor.downloadModel": {
21636
21986
  capName: "pipeline-executor",
@@ -21776,12 +22126,6 @@ Object.freeze({
21776
22126
  addonId: null,
21777
22127
  access: "create"
21778
22128
  },
21779
- "pipelineExecutor.resetToDefault": {
21780
- capName: "pipeline-executor",
21781
- capScope: "system",
21782
- addonId: null,
21783
- access: "delete"
21784
- },
21785
22129
  "pipelineExecutor.runAudioTest": {
21786
22130
  capName: "pipeline-executor",
21787
22131
  capScope: "system",
@@ -21842,12 +22186,6 @@ Object.freeze({
21842
22186
  addonId: null,
21843
22187
  access: "create"
21844
22188
  },
21845
- "pipelineOrchestrator.assignDecoder": {
21846
- capName: "pipeline-orchestrator",
21847
- capScope: "system",
21848
- addonId: null,
21849
- access: "create"
21850
- },
21851
22189
  "pipelineOrchestrator.assignPipeline": {
21852
22190
  capName: "pipeline-orchestrator",
21853
22191
  capScope: "system",
@@ -21926,18 +22264,6 @@ Object.freeze({
21926
22264
  addonId: null,
21927
22265
  access: "view"
21928
22266
  },
21929
- "pipelineOrchestrator.getDecoderAssignment": {
21930
- capName: "pipeline-orchestrator",
21931
- capScope: "system",
21932
- addonId: null,
21933
- access: "view"
21934
- },
21935
- "pipelineOrchestrator.getDecoderAssignments": {
21936
- capName: "pipeline-orchestrator",
21937
- capScope: "system",
21938
- addonId: null,
21939
- access: "view"
21940
- },
21941
22267
  "pipelineOrchestrator.getGlobalMetrics": {
21942
22268
  capName: "pipeline-orchestrator",
21943
22269
  capScope: "system",
@@ -21986,6 +22312,12 @@ Object.freeze({
21986
22312
  addonId: null,
21987
22313
  access: "delete"
21988
22314
  },
22315
+ "pipelineOrchestrator.resetNodePipelineDefaults": {
22316
+ capName: "pipeline-orchestrator",
22317
+ capScope: "system",
22318
+ addonId: null,
22319
+ access: "delete"
22320
+ },
21989
22321
  "pipelineOrchestrator.resolvePipeline": {
21990
22322
  capName: "pipeline-orchestrator",
21991
22323
  capScope: "system",
@@ -22058,12 +22390,6 @@ Object.freeze({
22058
22390
  addonId: null,
22059
22391
  access: "create"
22060
22392
  },
22061
- "pipelineOrchestrator.unassignDecoder": {
22062
- capName: "pipeline-orchestrator",
22063
- capScope: "system",
22064
- addonId: null,
22065
- access: "create"
22066
- },
22067
22393
  "pipelineOrchestrator.unassignPipeline": {
22068
22394
  capName: "pipeline-orchestrator",
22069
22395
  capScope: "system",
@@ -22118,6 +22444,12 @@ Object.freeze({
22118
22444
  addonId: null,
22119
22445
  access: "view"
22120
22446
  },
22447
+ "pipelineRunner.getNativeCrop": {
22448
+ capName: "pipeline-runner",
22449
+ capScope: "system",
22450
+ addonId: null,
22451
+ access: "view"
22452
+ },
22121
22453
  "pipelineRunner.reportMotion": {
22122
22454
  capName: "pipeline-runner",
22123
22455
  capScope: "system",
@@ -22370,6 +22702,36 @@ Object.freeze({
22370
22702
  addonId: null,
22371
22703
  access: "create"
22372
22704
  },
22705
+ "serverManagement.applyServerUpdate": {
22706
+ capName: "server-management",
22707
+ capScope: "system",
22708
+ addonId: null,
22709
+ access: "create"
22710
+ },
22711
+ "serverManagement.checkServerUpdate": {
22712
+ capName: "server-management",
22713
+ capScope: "system",
22714
+ addonId: null,
22715
+ access: "create"
22716
+ },
22717
+ "serverManagement.getServerPackageStatus": {
22718
+ capName: "server-management",
22719
+ capScope: "system",
22720
+ addonId: null,
22721
+ access: "view"
22722
+ },
22723
+ "serverManagement.restartServer": {
22724
+ capName: "server-management",
22725
+ capScope: "system",
22726
+ addonId: null,
22727
+ access: "create"
22728
+ },
22729
+ "serverManagement.rollbackServerUpdate": {
22730
+ capName: "server-management",
22731
+ capScope: "system",
22732
+ addonId: null,
22733
+ access: "create"
22734
+ },
22373
22735
  "settingsStore.count": {
22374
22736
  capName: "settings-store",
22375
22737
  capScope: "system",
@@ -22454,6 +22816,12 @@ Object.freeze({
22454
22816
  addonId: null,
22455
22817
  access: "view"
22456
22818
  },
22819
+ "snapshot.getSnapshotOverview": {
22820
+ capName: "snapshot",
22821
+ capScope: "device",
22822
+ addonId: null,
22823
+ access: "view"
22824
+ },
22457
22825
  "snapshot.invalidateCache": {
22458
22826
  capName: "snapshot",
22459
22827
  capScope: "device",
@@ -23132,6 +23500,12 @@ Object.freeze({
23132
23500
  addonId: null,
23133
23501
  access: "view"
23134
23502
  },
23503
+ "userPasskeys.beginDiscoverableAuthentication": {
23504
+ capName: "user-passkeys",
23505
+ capScope: "system",
23506
+ addonId: null,
23507
+ access: "view"
23508
+ },
23135
23509
  "userPasskeys.beginRegistration": {
23136
23510
  capName: "user-passkeys",
23137
23511
  capScope: "system",
@@ -23144,12 +23518,24 @@ Object.freeze({
23144
23518
  addonId: null,
23145
23519
  access: "view"
23146
23520
  },
23521
+ "userPasskeys.finishDiscoverableAuthentication": {
23522
+ capName: "user-passkeys",
23523
+ capScope: "system",
23524
+ addonId: null,
23525
+ access: "view"
23526
+ },
23147
23527
  "userPasskeys.finishRegistration": {
23148
23528
  capName: "user-passkeys",
23149
23529
  capScope: "system",
23150
23530
  addonId: null,
23151
23531
  access: "create"
23152
23532
  },
23533
+ "userPasskeys.getSecondFactorPreference": {
23534
+ capName: "user-passkeys",
23535
+ capScope: "system",
23536
+ addonId: null,
23537
+ access: "view"
23538
+ },
23153
23539
  "userPasskeys.listPasskeys": {
23154
23540
  capName: "user-passkeys",
23155
23541
  capScope: "system",
@@ -23162,6 +23548,12 @@ Object.freeze({
23162
23548
  addonId: null,
23163
23549
  access: "delete"
23164
23550
  },
23551
+ "userPasskeys.setSecondFactorPreference": {
23552
+ capName: "user-passkeys",
23553
+ capScope: "system",
23554
+ addonId: null,
23555
+ access: "create"
23556
+ },
23165
23557
  "vacuumControl.locate": {
23166
23558
  capName: "vacuum-control",
23167
23559
  capScope: "device",
@@ -23234,6 +23626,18 @@ Object.freeze({
23234
23626
  addonId: null,
23235
23627
  access: "view"
23236
23628
  },
23629
+ "viewerUi.getStaticDir": {
23630
+ capName: "viewer-ui",
23631
+ capScope: "system",
23632
+ addonId: null,
23633
+ access: "view"
23634
+ },
23635
+ "viewerUi.getVersion": {
23636
+ capName: "viewer-ui",
23637
+ capScope: "system",
23638
+ addonId: null,
23639
+ access: "view"
23640
+ },
23237
23641
  "waterHeater.setAway": {
23238
23642
  capName: "water-heater",
23239
23643
  capScope: "device",