@camstack/addon-provider-amcrest 0.1.6 → 0.1.8

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.mjs CHANGED
@@ -4634,7 +4634,7 @@ function _instanceof(cls, params = {}) {
4634
4634
  return inst;
4635
4635
  }
4636
4636
  //#endregion
4637
- //#region ../types/dist/sleep-Cc14_yxc.mjs
4637
+ //#region ../types/dist/sleep-BC9Yqte7.mjs
4638
4638
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4639
4639
  EventCategory["SystemBoot"] = "system.boot";
4640
4640
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -5355,10 +5355,6 @@ function hydrateField(field, values) {
5355
5355
  };
5356
5356
  }
5357
5357
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5358
- if (field.type === "password") return {
5359
- ...field,
5360
- value: ""
5361
- };
5362
5358
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5363
5359
  return {
5364
5360
  ...field,
@@ -6742,10 +6738,25 @@ function method(input, output, options) {
6742
6738
  timeoutMs: options?.timeoutMs
6743
6739
  };
6744
6740
  }
6741
+ /**
6742
+ * A wrapper/system-only method: served exclusively by the cap's system-level
6743
+ * provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
6744
+ * driver natives don't stub out a wrapper concern (e.g. a cross-device cache
6745
+ * overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
6746
+ */
6747
+ function systemMethod(input, output, options) {
6748
+ return {
6749
+ ...method(input, output, options),
6750
+ systemOnly: true
6751
+ };
6752
+ }
6745
6753
  /** Shorthand to define an event schema */
6746
6754
  function event(data) {
6747
6755
  return { data };
6748
6756
  }
6757
+ var StaticDirOutputSchema$1 = object({ staticDir: string() });
6758
+ var VersionOutputSchema$1 = object({ version: string() });
6759
+ method(_void(), StaticDirOutputSchema$1), method(_void(), VersionOutputSchema$1);
6749
6760
  var StaticDirOutputSchema = object({ staticDir: string() });
6750
6761
  var VersionOutputSchema = object({ version: string() });
6751
6762
  method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
@@ -11657,7 +11668,7 @@ var BoundingBoxSchema = object({
11657
11668
  w: number(),
11658
11669
  h: number()
11659
11670
  });
11660
- var SpatialDetectionSchema = object({
11671
+ object({
11661
11672
  class: string(),
11662
11673
  originalClass: string(),
11663
11674
  score: number(),
@@ -11832,6 +11843,7 @@ var PipelineAddonSchemaSchema = object({
11832
11843
  defaultModelId: string(),
11833
11844
  defaultModelIdByFormat: record(string(), string()).optional(),
11834
11845
  enabledByDefault: boolean().optional(),
11846
+ backfillIntoExistingOverrides: boolean().optional(),
11835
11847
  defaultConfidence: number(),
11836
11848
  group: string().optional(),
11837
11849
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -11848,11 +11860,6 @@ var PipelineSchemaSchema = object({
11848
11860
  selectedEngine: PipelineEngineChoiceSchema,
11849
11861
  slots: array(PipelineSlotSchemaSchema).readonly()
11850
11862
  });
11851
- var DetectorOutputSchema = object({
11852
- detections: array(SpatialDetectionSchema).readonly(),
11853
- inferenceMs: number(),
11854
- modelId: string()
11855
- });
11856
11863
  var EngineProvisioningSchema = object({
11857
11864
  runtimeId: _enum([
11858
11865
  "onnx",
@@ -11977,7 +11984,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11977
11984
  auth: "admin"
11978
11985
  }), method(object({ nodeId: string() }), object({
11979
11986
  success: literal(true),
11980
- regeneratedModelId: string().nullable()
11987
+ clearedDevices: number()
11981
11988
  }), {
11982
11989
  kind: "mutation",
11983
11990
  auth: "admin"
@@ -11998,10 +12005,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11998
12005
  modelId: string(),
11999
12006
  format: ModelFormatSchema$1
12000
12007
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
12001
- addonId: string(),
12002
- frame: FrameInputSchema,
12003
- config: record(string(), unknown()).optional()
12004
- }), DetectorOutputSchema), method(object({
12005
12008
  engine: PipelineEngineChoiceSchema.optional(),
12006
12009
  steps: array(PipelineStepInputSchema).min(1),
12007
12010
  frame: FrameInputSchema.optional(),
@@ -12180,6 +12183,25 @@ var zonesCapability = {
12180
12183
  runtimeState: object({ zones: array(ZoneSchema).readonly() })
12181
12184
  };
12182
12185
  /**
12186
+ * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
12187
+ * decode worker resolves it against the RETAINED native frame's real pixel dims,
12188
+ * so the caller supplies only the detection-res bbox divided by the detection
12189
+ * dims — no native resolution to plumb.
12190
+ */
12191
+ var NativeCropBboxSchema = object({
12192
+ x: number(),
12193
+ y: number(),
12194
+ w: number(),
12195
+ h: number()
12196
+ });
12197
+ /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
12198
+ var NativeCropResultSchema = object({
12199
+ /** Packed rgb (24-bit) pixels of the crop. */
12200
+ bytes: _instanceof(Uint8Array),
12201
+ width: number().int().positive(),
12202
+ height: number().int().positive()
12203
+ });
12204
+ /**
12183
12205
  * Per-camera tunable ranges + defaults. Single source of truth used
12184
12206
  * by both the Zod data schema (validation + default fallback) and
12185
12207
  * the device settings UI (slider min/max/step). Touch one place and
@@ -12435,7 +12457,11 @@ var RunnerLocalMetricsSchema = object({
12435
12457
  avgInferenceTimeMs: number(),
12436
12458
  queueDepth: number()
12437
12459
  });
12438
- 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());
12460
+ 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({
12461
+ handle: FrameHandleSchema,
12462
+ bbox: NativeCropBboxSchema,
12463
+ maxWidth: number().int().positive().optional()
12464
+ }), NativeCropResultSchema.nullable());
12439
12465
  /**
12440
12466
  * Hardware / firmware motion sensor cap — binary detected state plus
12441
12467
  * a timestamp of the last observation. Distinct from
@@ -15366,7 +15392,9 @@ var AddonPageDeclarationSchema$1 = object({
15366
15392
  icon: string(),
15367
15393
  path: string(),
15368
15394
  remoteName: string(),
15369
- bundle: string()
15395
+ bundle: string(),
15396
+ section: string().optional(),
15397
+ sectionLabel: string().optional()
15370
15398
  });
15371
15399
  var AddonPageInfoSchema = object({
15372
15400
  addonId: string(),
@@ -15406,7 +15434,18 @@ var AddonPageDeclarationSchema = object({
15406
15434
  * the static-file route can compute an mtime-based cache-buster URL
15407
15435
  * without a separate filesystem stat.
15408
15436
  */
15409
- bundle: string()
15437
+ bundle: string(),
15438
+ /**
15439
+ * Sidebar section this page docks into. Well-known ids: `'detection'`,
15440
+ * `'cluster'`, `'administration'` — the page renders inside that group.
15441
+ * Any OTHER string creates (or joins) a custom section rendered after
15442
+ * the built-in groups; its label comes from `sectionLabel` (first
15443
+ * declaration wins), falling back to the id. Absent → the legacy
15444
+ * "Addon Pages" group.
15445
+ */
15446
+ section: string().optional(),
15447
+ /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
15448
+ sectionLabel: string().optional()
15410
15449
  });
15411
15450
  method(_void(), array(AddonPageDeclarationSchema).readonly());
15412
15451
  var AddonHttpRouteSchema = object({
@@ -15622,6 +15661,17 @@ var WidgetMetadataSchema = object({
15622
15661
  deviceContext: boolean().default(false),
15623
15662
  integrationContext: boolean().default(false)
15624
15663
  }),
15664
+ /**
15665
+ * Loadable BEFORE authentication. The normal widget registry listing
15666
+ * (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
15667
+ * (the login page) cannot discover a widget through it. A widget that
15668
+ * declares `preAuth: true` marks itself as safe to mount on a pre-auth
15669
+ * screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
15670
+ * login-method contribution channel (see `login-method.cap.ts`) rather
15671
+ * than the authenticated registry, and its bundle is served by the
15672
+ * public `/api/addon-widgets/:addonId/*` static route. Defaults false.
15673
+ */
15674
+ preAuth: boolean().optional().default(false),
15625
15675
  /** Dashboard placement HINTS (operator can override per instance). */
15626
15676
  defaultSize: WidgetSizeEnum.default("md"),
15627
15677
  allowedSizes: array(WidgetSizeEnum).readonly().default([
@@ -15923,6 +15973,66 @@ method(object({
15923
15973
  password: string()
15924
15974
  }), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
15925
15975
  /**
15976
+ * `login-method` — collection cap through which auth addons contribute
15977
+ * their pre-auth login surfaces to the login page. This is the SINGLE,
15978
+ * generic mechanism that supersedes the dead `auth.listProviders` reader:
15979
+ * every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
15980
+ * `login-method` provider and the PUBLIC `auth.listLoginMethods`
15981
+ * procedure aggregates them for the unauthenticated login page.
15982
+ *
15983
+ * A contribution is a discriminated union on `kind`:
15984
+ *
15985
+ * - `redirect` — a declarative button. The login page renders a generic
15986
+ * button that navigates to `startUrl` (an addon-owned HTTP route).
15987
+ * Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
15988
+ * ZERO shell-side JS. A future SSO addon plugs in the same way — the
15989
+ * login page needs NO change.
15990
+ *
15991
+ * - `widget` — a Module-Federation widget the login page mounts (via
15992
+ * `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
15993
+ * login ceremony, which must run `@simplewebauthn/browser` INSIDE the
15994
+ * addon bundle. The referenced widget also declares `preAuth: true` in
15995
+ * its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
15996
+ * stamps a public `bundleUrl` from `addonId` + `bundle`.
15997
+ *
15998
+ * Every contribution carries a `stage`:
15999
+ * - `primary` — shown on the first credentials screen (OIDC /
16000
+ * magic-link buttons; a future usernameless passkey).
16001
+ * - `second-factor` — shown AFTER the password leg, gated on the
16002
+ * returned `factors` (passkey-as-2FA today).
16003
+ *
16004
+ * `mount: skip` — the cap is read server-side by the core auth router
16005
+ * (`registry.getCollection('login-method')`), never mounted as its own
16006
+ * tRPC router.
16007
+ */
16008
+ /** When a login method renders in the two-phase login flow. */
16009
+ var LoginStageEnum = _enum(["primary", "second-factor"]);
16010
+ /** One login-method contribution — redirect button OR pre-auth widget. */
16011
+ var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
16012
+ kind: literal("redirect"),
16013
+ /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
16014
+ id: string(),
16015
+ /** Operator-facing button label. */
16016
+ label: string(),
16017
+ /** lucide-react icon name. */
16018
+ icon: string().optional(),
16019
+ /** Addon-owned HTTP route the button navigates to (GET). */
16020
+ startUrl: string(),
16021
+ stage: LoginStageEnum
16022
+ }), object({
16023
+ kind: literal("widget"),
16024
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
16025
+ id: string(),
16026
+ /** Owning addon id — drives the public bundle URL + the MF namespace. */
16027
+ addonId: string(),
16028
+ /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
16029
+ bundle: string(),
16030
+ /** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
16031
+ remote: WidgetRemoteSchema,
16032
+ stage: LoginStageEnum
16033
+ })]);
16034
+ method(_void(), array(LoginMethodContributionSchema).readonly());
16035
+ /**
15926
16036
  * Orchestrator-side destination metadata. The orchestrator computes
15927
16037
  * `id = <addonId>:<subId>` from its provider lookup so consumers
15928
16038
  * (admin UI, restore flow) see one canonical key.
@@ -18026,7 +18136,17 @@ var TrackSchema = object({
18026
18136
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
18027
18137
  totalDistance: number(),
18028
18138
  state: TrackStateSchema,
18029
- active: boolean()
18139
+ active: boolean(),
18140
+ /** Deterministic key-event importance score in [0,1] (server-computed at
18141
+ * track expiry, recomputed on late label). Absent on legacy rows written
18142
+ * before scoring shipped — consumers degrade to absence / compute-on-read. */
18143
+ importance: number().optional(),
18144
+ /** Id of the track's highest-confidence ObjectEvent (its representative
18145
+ * "best" frame). Absent when the track produced no object events. */
18146
+ bestEventId: string().optional(),
18147
+ /** Tag of the importance sub-signal that dominated the score
18148
+ * (identity|dwell|proximity|class|confidence|travel|zone). */
18149
+ importanceReason: string().optional()
18030
18150
  });
18031
18151
  var BaseEventFields = {
18032
18152
  id: string(),
@@ -18091,8 +18211,18 @@ var ObjectEventSchema = object({
18091
18211
  frameHeight: number().optional(),
18092
18212
  /** MediaStore key for the crop attached to this event (if any). */
18093
18213
  mediaKey: string().optional(),
18214
+ /** Design B: MediaStore key of the track's native-resolution key frame (the
18215
+ * best-detection full frame). Resolve via the event-media data-plane
18216
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
18217
+ * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
18218
+ * sources — consumers fall back to `mediaKey` (the tight crop). */
18219
+ keyFrameMediaKey: string().optional(),
18094
18220
  /** Populated by B5 (recording playback URL for this event). */
18095
- mediaUrl: string().optional()
18221
+ mediaUrl: string().optional(),
18222
+ /** The parent track's key-event importance [0,1], propagated to every object
18223
+ * event of the track (so an event row can be sorted by importance without a
18224
+ * track join). Absent on legacy rows / before the track was scored. */
18225
+ importance: number().optional()
18096
18226
  });
18097
18227
  var AudioEventSchema = object({
18098
18228
  ...BaseEventFields,
@@ -18116,7 +18246,8 @@ var MediaFileKindEnum = _enum([
18116
18246
  "fullFrame",
18117
18247
  "fullFrameBoxed",
18118
18248
  "faceCrop",
18119
- "plateCrop"
18249
+ "plateCrop",
18250
+ "keyFrame"
18120
18251
  ]);
18121
18252
  var MediaFileSchema = object({
18122
18253
  key: string(),
@@ -18137,6 +18268,32 @@ var DeviceEventQueryInput = object({
18137
18268
  projection: _enum(["full", "slim"]).optional()
18138
18269
  });
18139
18270
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
18271
+ var KeyEventQueryInput = object({
18272
+ deviceId: number(),
18273
+ /** Window lower bound (track firstSeen ≥ since). */
18274
+ since: number(),
18275
+ /** Window upper bound (track firstSeen ≤ until). */
18276
+ until: number(),
18277
+ limit: number().int().min(1).max(200).default(50),
18278
+ /** Drop tracks scoring below this importance. */
18279
+ minImportance: number().min(0).max(1).optional(),
18280
+ /** Restrict to a single class (e.g. 'person'). */
18281
+ classFilter: string().optional()
18282
+ });
18283
+ var KeyEventSchema = object({
18284
+ /** The representative event id (the track's best ObjectEvent, else its trackId). */
18285
+ id: string(),
18286
+ trackId: string(),
18287
+ /** Track start time (firstSeen). */
18288
+ timestamp: number(),
18289
+ className: string(),
18290
+ label: string().optional(),
18291
+ importance: number(),
18292
+ /** Highest-confidence ObjectEvent id for the track (empty when none). */
18293
+ bestEventId: string(),
18294
+ /** Track lifetime in ms (lastSeen - firstSeen). */
18295
+ windowMs: number().optional()
18296
+ });
18140
18297
  var TrackedDetectionSchema = object({
18141
18298
  trackId: string(),
18142
18299
  className: string(),
@@ -18166,7 +18323,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18166
18323
  }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
18167
18324
  kind: "mutation",
18168
18325
  auth: "admin"
18169
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
18326
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
18170
18327
  deviceId: number(),
18171
18328
  since: number(),
18172
18329
  until: number(),
@@ -18240,7 +18397,12 @@ var AgentPipelineSettingsSchema = object({
18240
18397
  detectWeight: number().positive().optional(),
18241
18398
  /** Node is eligible to run the detection pipeline (decode + inference). */
18242
18399
  detect: boolean().optional(),
18243
- /** Node is eligible to host decoder sessions. */
18400
+ /**
18401
+ * DEPRECATED AND IGNORED. Decode is always co-located with its frame
18402
+ * consumer, so decode eligibility IS detect eligibility. Kept optional in
18403
+ * the schema ONLY so persisted stores written before the removal still
18404
+ * parse — no code reads it and no write path emits it.
18405
+ */
18244
18406
  decode: boolean().optional(),
18245
18407
  /** Node is eligible to run audio-analyzer sessions. */
18246
18408
  audio: boolean().optional(),
@@ -18301,25 +18463,6 @@ var PipelineAssignmentSchema = object({
18301
18463
  assignedAt: number()
18302
18464
  });
18303
18465
  /**
18304
- * Decoder placement record. Symmetric to `PipelineAssignmentSchema` but for
18305
- * the decoder-node placement domain (`balanceDecoder` decision: manual pin
18306
- * → co-located with pipeline → capacity).
18307
- */
18308
- var DecoderAssignmentSchema = object({
18309
- deviceId: number(),
18310
- /** Moleculer node id of the decoder provider currently responsible for this camera. */
18311
- decoderNodeId: string(),
18312
- /** True when the assignment was set manually via `assignDecoder`, false when chosen by the balancer. */
18313
- pinned: boolean(),
18314
- /** Why this assignment was made — useful for debugging the decoder balancer. */
18315
- reason: _enum([
18316
- "manual",
18317
- "co-located",
18318
- "capacity",
18319
- "hardware-affinity"
18320
- ])
18321
- });
18322
- /**
18323
18466
  * Per-agent load summary surfaced to the load balancer + dashboards.
18324
18467
  * Aggregated from each runner's `getLocalLoad` cap call.
18325
18468
  */
@@ -18525,15 +18668,6 @@ method(object({
18525
18668
  }), method(_void(), IngestOwnerSchema), method(object({
18526
18669
  deviceId: number(),
18527
18670
  nodeId: string()
18528
- }), _void(), {
18529
- kind: "mutation",
18530
- auth: "admin"
18531
- }), method(object({ deviceId: number() }), _void(), {
18532
- kind: "mutation",
18533
- auth: "admin"
18534
- }), method(_void(), array(DecoderAssignmentSchema).readonly()), method(object({
18535
- deviceId: number(),
18536
- nodeId: string()
18537
18671
  }), object({ success: literal(true) }), {
18538
18672
  kind: "mutation",
18539
18673
  auth: "admin"
@@ -18552,10 +18686,7 @@ method(object({
18552
18686
  nodeId: string(),
18553
18687
  pinned: boolean(),
18554
18688
  assignedAt: number()
18555
- }))), method(object({
18556
- deviceId: number(),
18557
- pipelineNodeId: string().optional()
18558
- }), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
18689
+ }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
18559
18690
  nodeId: string(),
18560
18691
  settings: AgentPipelineSettingsSchema
18561
18692
  })).readonly()), method(object({
@@ -18585,7 +18716,6 @@ method(object({
18585
18716
  }), method(object({
18586
18717
  agentNodeId: string(),
18587
18718
  detect: boolean().nullable().optional(),
18588
- decode: boolean().nullable().optional(),
18589
18719
  audio: boolean().nullable().optional(),
18590
18720
  ingest: boolean().nullable().optional()
18591
18721
  }), object({ success: literal(true) }), {
@@ -18597,6 +18727,15 @@ method(object({
18597
18727
  }), object({ success: literal(true) }), {
18598
18728
  kind: "mutation",
18599
18729
  auth: "admin"
18730
+ }), method(object({ agentNodeId: string() }), object({
18731
+ success: literal(true),
18732
+ /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
18733
+ effectiveModelId: string().nullable(),
18734
+ /** Number of cameras whose node-scoped overrides were cleared. */
18735
+ clearedCameraOverrides: number()
18736
+ }), {
18737
+ kind: "mutation",
18738
+ auth: "admin"
18600
18739
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
18601
18740
  deviceId: number(),
18602
18741
  addonId: string(),
@@ -18642,6 +18781,131 @@ method(object({
18642
18781
  auth: "admin"
18643
18782
  });
18644
18783
  /**
18784
+ * server-management — per-NODE singleton capability for a node's ROOT
18785
+ * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
18786
+ * agents).
18787
+ *
18788
+ * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
18789
+ * on agents) carries the whole software stack in its npm dep tree, so ONE
18790
+ * version describes the node. Updates install into
18791
+ * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
18792
+ * starter (probation boot + auto-rollback to N-1).
18793
+ *
18794
+ * Providers:
18795
+ * - HUB: `ServerUpdateService` behind the `server-provided` mount
18796
+ * (`buildServerProviders` in trpc.router.ts) — the default target for
18797
+ * unpinned calls.
18798
+ * - AGENT: `AgentUpdateService` registered by the agent bootstrap under
18799
+ * the synthetic `agent-runtime` addonId and declared in the agent's
18800
+ * `$hub.registerNode` manifest.
18801
+ *
18802
+ * Node routing: singleton caps get the codegen/runtime-builder `nodeId`
18803
+ * injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
18804
+ * SDK) routes the call to that node's provider via the standard remote
18805
+ * proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
18806
+ * in-process provider lookup). No `nodeId` → the hub's own provider.
18807
+ *
18808
+ * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
18809
+ */
18810
+ /**
18811
+ * Where the running hub's code was loaded from:
18812
+ * - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
18813
+ * plain resolution and runtime updates are refused.
18814
+ * - `baked` — the immutable image seed closure (no data-dir root active).
18815
+ * - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
18816
+ */
18817
+ var ServerBootModeSchema = _enum([
18818
+ "workspace",
18819
+ "baked",
18820
+ "data-root"
18821
+ ]);
18822
+ /**
18823
+ * Update lifecycle state:
18824
+ * - `idle` / `checking` / `staging` — steady / in-flight registry work.
18825
+ * - `pending-restart` — a version is staged and the node has NOT yet
18826
+ * restarted onto it (still running the OLD version).
18827
+ * - `awaiting-confirmation` — the node HAS restarted onto the staged version
18828
+ * (it is the active probation boot) and is waiting to confirm boot-health.
18829
+ * Apply/rollback are refused in this state and the node must NOT be
18830
+ * manually restarted, or the probation boot auto-rolls-back.
18831
+ */
18832
+ var ServerUpdateStateSchema = _enum([
18833
+ "idle",
18834
+ "checking",
18835
+ "staging",
18836
+ "pending-restart",
18837
+ "awaiting-confirmation"
18838
+ ]);
18839
+ var ServerRollbackInfoSchema = object({
18840
+ /** The version that failed (or was manually rolled back). */
18841
+ fromVersion: string(),
18842
+ /** The version rolled back to; null = the baked seed. */
18843
+ toVersion: string().nullable(),
18844
+ atMs: number(),
18845
+ reason: string()
18846
+ });
18847
+ var ServerPackageStatusSchema = object({
18848
+ /** Root package name (`@camstack/server` on the hub). */
18849
+ packageName: string(),
18850
+ /** Version of the code the running process ACTUALLY loaded. */
18851
+ runningVersion: string().nullable(),
18852
+ /** Node.js runtime version the node's process runs on (`process.versions.node`). */
18853
+ nodeRuntimeVersion: string().nullable(),
18854
+ /** Active data-dir root version; null when booted from seed/workspace. */
18855
+ activeVersion: string().nullable(),
18856
+ /** N-1 version kept for rollback; null when no previous version exists. */
18857
+ previousVersion: string().nullable(),
18858
+ /** Version of the immutable baked seed closure (image fallback). */
18859
+ seedVersion: string().nullable(),
18860
+ /** Latest registry version from the most recent check (null = never checked). */
18861
+ latestVersion: string().nullable(),
18862
+ updateAvailable: boolean(),
18863
+ bootMode: ServerBootModeSchema,
18864
+ updateState: ServerUpdateStateSchema,
18865
+ /** Version staged + awaiting its probation boot, when one is pending. */
18866
+ pendingVersion: string().nullable(),
18867
+ /** Set when the last freshly-activated version failed its boot health-check. */
18868
+ rolledBack: ServerRollbackInfoSchema.nullable(),
18869
+ /**
18870
+ * True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
18871
+ * hub is running from the baked seed (or workspace) while installed data-dir
18872
+ * versions are being IGNORED. Surfaced as a warning in the UI.
18873
+ */
18874
+ stateFileCorrupt: boolean(),
18875
+ lastCheckedAtMs: number().nullable()
18876
+ });
18877
+ var ServerUpdateCheckResultSchema = object({
18878
+ packageName: string(),
18879
+ runningVersion: string().nullable(),
18880
+ latestVersion: string().nullable(),
18881
+ updateAvailable: boolean(),
18882
+ checkedAtMs: number(),
18883
+ /** Non-null when the registry lookup failed (offline, bad registry, …). */
18884
+ error: string().nullable()
18885
+ });
18886
+ var ServerUpdateActionResultSchema = object({
18887
+ accepted: boolean(),
18888
+ targetVersion: string().nullable(),
18889
+ /** True when a graceful restart was scheduled to apply the change. */
18890
+ restarting: boolean(),
18891
+ message: string()
18892
+ });
18893
+ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
18894
+ kind: "mutation",
18895
+ auth: "admin"
18896
+ }), method(object({
18897
+ /** Explicit target version; omitted = latest from the registry. */
18898
+ version: string().optional() }), ServerUpdateActionResultSchema, {
18899
+ kind: "mutation",
18900
+ auth: "admin"
18901
+ }), method(_void(), ServerUpdateActionResultSchema, {
18902
+ kind: "mutation",
18903
+ auth: "admin"
18904
+ }), method(_void(), ServerUpdateActionResultSchema, {
18905
+ kind: "mutation",
18906
+ auth: "admin"
18907
+ });
18908
+ /**
18645
18909
  * Query filter for settings-store collections.
18646
18910
  */
18647
18911
  var QueryFilterSchema = object({
@@ -18863,7 +19127,20 @@ var snapshotCapability = {
18863
19127
  invalidateCache: method(object({ deviceId: number() }), _void(), {
18864
19128
  kind: "mutation",
18865
19129
  auth: "admin"
18866
- })
19130
+ }),
19131
+ /**
19132
+ * Cache-only batch overview — answers from the wrapper's in-memory cache in
19133
+ * O(n) and NEVER triggers a capture. Lets a grid skip requesting images for
19134
+ * devices that never produced a frame, and gives it an ETag per device for
19135
+ * conditional (304-able) image fetches. `lastCapturedAt`/`cacheAgeMs`/`etag`
19136
+ * are null for a device with no cached frame.
19137
+ */
19138
+ getSnapshotOverview: systemMethod(object({ deviceIds: array(number()).min(1).max(200) }), array(object({
19139
+ deviceId: number(),
19140
+ lastCapturedAt: number().nullable(),
19141
+ cacheAgeMs: number().nullable(),
19142
+ etag: string().nullable()
19143
+ })))
18867
19144
  },
18868
19145
  status: {
18869
19146
  schema: SnapshotStatusSchema,
@@ -19120,10 +19397,32 @@ method(_void(), array(TurnServerSchema).readonly());
19120
19397
  * b. `finishAuthentication({userId, response})` → server verifies
19121
19398
  * the assertion, bumps the credential counter, returns ok.
19122
19399
  *
19400
+ * 2b. Usernameless (discoverable-credential) authentication — the
19401
+ * passkey IS the primary factor, no password leg:
19402
+ * a. `beginDiscoverableAuthentication({})` → assertion options with
19403
+ * EMPTY `allowCredentials` (the browser offers every resident
19404
+ * passkey it holds for this RP) + `userVerification: 'required'`
19405
+ * (the passkey replaces both factors, so UV is mandatory).
19406
+ * The challenge is stored server-side, NOT bound to any user.
19407
+ * b. `finishDiscoverableAuthentication({response})` → the provider
19408
+ * resolves the credential by the response's credential id,
19409
+ * verifies the assertion against the stored challenge + that
19410
+ * credential's public key/counter, and returns the OWNING
19411
+ * `userId` — the caller (core auth router) mints the session.
19412
+ *
19123
19413
  * 3. Management:
19124
19414
  * - `listPasskeys({userId})` — enumerate user's enrolled credentials.
19125
19415
  * - `removePasskey({userId, credentialId})` — revoke one credential.
19126
19416
  *
19417
+ * 4. Second-factor preference (opt-in, default OFF):
19418
+ * Enrolling a passkey only enables passkey-FIRST sign-in. It is
19419
+ * demanded as a second factor after a password login ONLY when the
19420
+ * user explicitly opts in via `setSecondFactorPreference`.
19421
+ * - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
19422
+ * row ⇒ `enabled: false`).
19423
+ * - `setSecondFactorPreference({userId, enabled})` — persisted by
19424
+ * the providing addon beside its credentials.
19425
+ *
19127
19426
  * Challenges are short-lived (5 min, in-memory). The cap is internal —
19128
19427
  * the admin-ui composes the begin/finish round-trip and never exposes
19129
19428
  * the cap to non-admins.
@@ -19166,6 +19465,17 @@ method(object({
19166
19465
  }), object({ verified: boolean() }), {
19167
19466
  kind: "mutation",
19168
19467
  access: "view"
19468
+ }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
19469
+ kind: "mutation",
19470
+ access: "view"
19471
+ }), method(object({
19472
+ /** AuthenticationResponseJSON from the browser. */
19473
+ response: record(string(), unknown()) }), object({
19474
+ verified: boolean(),
19475
+ userId: string().nullable()
19476
+ }), {
19477
+ kind: "mutation",
19478
+ access: "view"
19169
19479
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
19170
19480
  userId: string(),
19171
19481
  credentialId: string()
@@ -19173,6 +19483,13 @@ method(object({
19173
19483
  kind: "mutation",
19174
19484
  auth: "admin",
19175
19485
  access: "delete"
19486
+ }), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
19487
+ userId: string(),
19488
+ enabled: boolean()
19489
+ }), object({ success: literal(true) }), {
19490
+ kind: "mutation",
19491
+ auth: "admin",
19492
+ access: "create"
19176
19493
  });
19177
19494
  /**
19178
19495
  * `videoclips` — the unified, navigable-clip surface for a camera.
@@ -19974,7 +20291,17 @@ var FaceInfoSchema = object({
19974
20291
  recognizedIdentityId: string().optional(),
19975
20292
  identityName: string().optional(),
19976
20293
  assigned: boolean(),
19977
- base64: string().optional()
20294
+ base64: string().optional(),
20295
+ /** Design B: the face bbox (pixel space) on the key frame — lets a detail
20296
+ * view draw the box over the native `keyFrameMediaKey` frame. Absent on
20297
+ * legacy rows written before design B. */
20298
+ faceBbox: BoundingBoxSchema.optional(),
20299
+ /** Design B: MediaStore key of the track's native-resolution key frame.
20300
+ * Fetch the native JPEG via the event-media data-plane
20301
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
20302
+ * track produced no key frame (e.g. native/onboard source) — the UI falls
20303
+ * back to the inline `base64` face crop. */
20304
+ keyFrameMediaKey: string().optional()
19978
20305
  });
19979
20306
  var FaceFilterEnum = _enum([
19980
20307
  "unassigned",
@@ -20671,6 +20998,16 @@ var TopologyCategorySchema = object({
20671
20998
  healthy: number(),
20672
20999
  addons: array(TopologyCategoryAddonSchema).readonly()
20673
21000
  });
21001
+ /**
21002
+ * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
21003
+ * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
21004
+ * version visibility for the Server management surface. Nullable: offline
21005
+ * rows and pre-phase-2 nodes report none.
21006
+ */
21007
+ var TopologyRootPackageSchema = object({
21008
+ name: string(),
21009
+ version: string()
21010
+ });
20674
21011
  var TopologyNodeSchema = object({
20675
21012
  id: string(),
20676
21013
  name: string(),
@@ -20694,7 +21031,8 @@ var TopologyNodeSchema = object({
20694
21031
  status: string()
20695
21032
  })).readonly(),
20696
21033
  processes: array(TopologyProcessSchema).readonly(),
20697
- categories: array(TopologyCategorySchema).readonly()
21034
+ categories: array(TopologyCategorySchema).readonly(),
21035
+ rootPackage: TopologyRootPackageSchema.nullable()
20698
21036
  });
20699
21037
  var CapUsageEdgeSchema = object({
20700
21038
  callerAddonId: string(),
@@ -23793,6 +24131,12 @@ Object.freeze({
23793
24131
  addonId: null,
23794
24132
  access: "create"
23795
24133
  },
24134
+ "loginMethod.getLoginMethods": {
24135
+ capName: "login-method",
24136
+ capScope: "system",
24137
+ addonId: null,
24138
+ access: "view"
24139
+ },
23796
24140
  "mediaPlayer.next": {
23797
24141
  capName: "media-player",
23798
24142
  capScope: "device",
@@ -24375,6 +24719,12 @@ Object.freeze({
24375
24719
  addonId: null,
24376
24720
  access: "view"
24377
24721
  },
24722
+ "pipelineAnalytics.getKeyEvents": {
24723
+ capName: "pipeline-analytics",
24724
+ capScope: "device",
24725
+ addonId: null,
24726
+ access: "view"
24727
+ },
24378
24728
  "pipelineAnalytics.getMotionEvents": {
24379
24729
  capName: "pipeline-analytics",
24380
24730
  capScope: "device",
@@ -24423,23 +24773,23 @@ Object.freeze({
24423
24773
  addonId: null,
24424
24774
  access: "create"
24425
24775
  },
24426
- "pipelineExecutor.deleteModel": {
24776
+ "pipelineExecutor.clearDeviceOverrides": {
24427
24777
  capName: "pipeline-executor",
24428
24778
  capScope: "system",
24429
24779
  addonId: null,
24430
24780
  access: "delete"
24431
24781
  },
24432
- "pipelineExecutor.deleteTemplate": {
24782
+ "pipelineExecutor.deleteModel": {
24433
24783
  capName: "pipeline-executor",
24434
24784
  capScope: "system",
24435
24785
  addonId: null,
24436
24786
  access: "delete"
24437
24787
  },
24438
- "pipelineExecutor.detect": {
24788
+ "pipelineExecutor.deleteTemplate": {
24439
24789
  capName: "pipeline-executor",
24440
24790
  capScope: "system",
24441
24791
  addonId: null,
24442
- access: "view"
24792
+ access: "delete"
24443
24793
  },
24444
24794
  "pipelineExecutor.downloadModel": {
24445
24795
  capName: "pipeline-executor",
@@ -24585,12 +24935,6 @@ Object.freeze({
24585
24935
  addonId: null,
24586
24936
  access: "create"
24587
24937
  },
24588
- "pipelineExecutor.resetToDefault": {
24589
- capName: "pipeline-executor",
24590
- capScope: "system",
24591
- addonId: null,
24592
- access: "delete"
24593
- },
24594
24938
  "pipelineExecutor.runAudioTest": {
24595
24939
  capName: "pipeline-executor",
24596
24940
  capScope: "system",
@@ -24651,12 +24995,6 @@ Object.freeze({
24651
24995
  addonId: null,
24652
24996
  access: "create"
24653
24997
  },
24654
- "pipelineOrchestrator.assignDecoder": {
24655
- capName: "pipeline-orchestrator",
24656
- capScope: "system",
24657
- addonId: null,
24658
- access: "create"
24659
- },
24660
24998
  "pipelineOrchestrator.assignPipeline": {
24661
24999
  capName: "pipeline-orchestrator",
24662
25000
  capScope: "system",
@@ -24735,18 +25073,6 @@ Object.freeze({
24735
25073
  addonId: null,
24736
25074
  access: "view"
24737
25075
  },
24738
- "pipelineOrchestrator.getDecoderAssignment": {
24739
- capName: "pipeline-orchestrator",
24740
- capScope: "system",
24741
- addonId: null,
24742
- access: "view"
24743
- },
24744
- "pipelineOrchestrator.getDecoderAssignments": {
24745
- capName: "pipeline-orchestrator",
24746
- capScope: "system",
24747
- addonId: null,
24748
- access: "view"
24749
- },
24750
25076
  "pipelineOrchestrator.getGlobalMetrics": {
24751
25077
  capName: "pipeline-orchestrator",
24752
25078
  capScope: "system",
@@ -24795,6 +25121,12 @@ Object.freeze({
24795
25121
  addonId: null,
24796
25122
  access: "delete"
24797
25123
  },
25124
+ "pipelineOrchestrator.resetNodePipelineDefaults": {
25125
+ capName: "pipeline-orchestrator",
25126
+ capScope: "system",
25127
+ addonId: null,
25128
+ access: "delete"
25129
+ },
24798
25130
  "pipelineOrchestrator.resolvePipeline": {
24799
25131
  capName: "pipeline-orchestrator",
24800
25132
  capScope: "system",
@@ -24867,12 +25199,6 @@ Object.freeze({
24867
25199
  addonId: null,
24868
25200
  access: "create"
24869
25201
  },
24870
- "pipelineOrchestrator.unassignDecoder": {
24871
- capName: "pipeline-orchestrator",
24872
- capScope: "system",
24873
- addonId: null,
24874
- access: "create"
24875
- },
24876
25202
  "pipelineOrchestrator.unassignPipeline": {
24877
25203
  capName: "pipeline-orchestrator",
24878
25204
  capScope: "system",
@@ -24927,6 +25253,12 @@ Object.freeze({
24927
25253
  addonId: null,
24928
25254
  access: "view"
24929
25255
  },
25256
+ "pipelineRunner.getNativeCrop": {
25257
+ capName: "pipeline-runner",
25258
+ capScope: "system",
25259
+ addonId: null,
25260
+ access: "view"
25261
+ },
24930
25262
  "pipelineRunner.reportMotion": {
24931
25263
  capName: "pipeline-runner",
24932
25264
  capScope: "system",
@@ -25179,6 +25511,36 @@ Object.freeze({
25179
25511
  addonId: null,
25180
25512
  access: "create"
25181
25513
  },
25514
+ "serverManagement.applyServerUpdate": {
25515
+ capName: "server-management",
25516
+ capScope: "system",
25517
+ addonId: null,
25518
+ access: "create"
25519
+ },
25520
+ "serverManagement.checkServerUpdate": {
25521
+ capName: "server-management",
25522
+ capScope: "system",
25523
+ addonId: null,
25524
+ access: "create"
25525
+ },
25526
+ "serverManagement.getServerPackageStatus": {
25527
+ capName: "server-management",
25528
+ capScope: "system",
25529
+ addonId: null,
25530
+ access: "view"
25531
+ },
25532
+ "serverManagement.restartServer": {
25533
+ capName: "server-management",
25534
+ capScope: "system",
25535
+ addonId: null,
25536
+ access: "create"
25537
+ },
25538
+ "serverManagement.rollbackServerUpdate": {
25539
+ capName: "server-management",
25540
+ capScope: "system",
25541
+ addonId: null,
25542
+ access: "create"
25543
+ },
25182
25544
  "settingsStore.count": {
25183
25545
  capName: "settings-store",
25184
25546
  capScope: "system",
@@ -25263,6 +25625,12 @@ Object.freeze({
25263
25625
  addonId: null,
25264
25626
  access: "view"
25265
25627
  },
25628
+ "snapshot.getSnapshotOverview": {
25629
+ capName: "snapshot",
25630
+ capScope: "device",
25631
+ addonId: null,
25632
+ access: "view"
25633
+ },
25266
25634
  "snapshot.invalidateCache": {
25267
25635
  capName: "snapshot",
25268
25636
  capScope: "device",
@@ -25941,6 +26309,12 @@ Object.freeze({
25941
26309
  addonId: null,
25942
26310
  access: "view"
25943
26311
  },
26312
+ "userPasskeys.beginDiscoverableAuthentication": {
26313
+ capName: "user-passkeys",
26314
+ capScope: "system",
26315
+ addonId: null,
26316
+ access: "view"
26317
+ },
25944
26318
  "userPasskeys.beginRegistration": {
25945
26319
  capName: "user-passkeys",
25946
26320
  capScope: "system",
@@ -25953,12 +26327,24 @@ Object.freeze({
25953
26327
  addonId: null,
25954
26328
  access: "view"
25955
26329
  },
26330
+ "userPasskeys.finishDiscoverableAuthentication": {
26331
+ capName: "user-passkeys",
26332
+ capScope: "system",
26333
+ addonId: null,
26334
+ access: "view"
26335
+ },
25956
26336
  "userPasskeys.finishRegistration": {
25957
26337
  capName: "user-passkeys",
25958
26338
  capScope: "system",
25959
26339
  addonId: null,
25960
26340
  access: "create"
25961
26341
  },
26342
+ "userPasskeys.getSecondFactorPreference": {
26343
+ capName: "user-passkeys",
26344
+ capScope: "system",
26345
+ addonId: null,
26346
+ access: "view"
26347
+ },
25962
26348
  "userPasskeys.listPasskeys": {
25963
26349
  capName: "user-passkeys",
25964
26350
  capScope: "system",
@@ -25971,6 +26357,12 @@ Object.freeze({
25971
26357
  addonId: null,
25972
26358
  access: "delete"
25973
26359
  },
26360
+ "userPasskeys.setSecondFactorPreference": {
26361
+ capName: "user-passkeys",
26362
+ capScope: "system",
26363
+ addonId: null,
26364
+ access: "create"
26365
+ },
25974
26366
  "vacuumControl.locate": {
25975
26367
  capName: "vacuum-control",
25976
26368
  capScope: "device",
@@ -26043,6 +26435,18 @@ Object.freeze({
26043
26435
  addonId: null,
26044
26436
  access: "view"
26045
26437
  },
26438
+ "viewerUi.getStaticDir": {
26439
+ capName: "viewer-ui",
26440
+ capScope: "system",
26441
+ addonId: null,
26442
+ access: "view"
26443
+ },
26444
+ "viewerUi.getVersion": {
26445
+ capName: "viewer-ui",
26446
+ capScope: "system",
26447
+ addonId: null,
26448
+ access: "view"
26449
+ },
26046
26450
  "waterHeater.setAway": {
26047
26451
  capName: "water-heater",
26048
26452
  capScope: "device",