@camstack/addon-pipeline 1.2.39 → 1.2.41

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 (34) hide show
  1. package/dist/audio-analyzer/index.js +1 -1
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/detection-pipeline/index.js +2 -2
  4. package/dist/detection-pipeline/index.mjs +2 -2
  5. package/dist/{dist-BtAvtroH.js → dist-BS7wLqoV.js} +499 -10
  6. package/dist/{dist-COgGdFMv.mjs → dist-DvUTPZ8J.mjs} +499 -10
  7. package/dist/{event-loop-stall-monitor-shfwi1_b.js → event-loop-stall-monitor-C5P2bcwP.js} +1 -1
  8. package/dist/{event-loop-stall-monitor-naFYvcOO.mjs → event-loop-stall-monitor-a2u9e1qx.mjs} +1 -1
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/pipeline-runner/index.js +2 -2
  12. package/dist/pipeline-runner/index.mjs +2 -2
  13. package/dist/recorder/index.js +1 -1
  14. package/dist/recorder/index.mjs +1 -1
  15. package/dist/session-decode/decode-worker-child.js +39 -2
  16. package/dist/session-decode/decode-worker-child.mjs +39 -2
  17. package/dist/stream-broker/_stub.js +2 -2
  18. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CjrKd4xX.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CS82x0lt.mjs} +3 -3
  19. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CDzxDzcv.mjs +26 -0
  20. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CciPNnL7.mjs +26 -0
  21. package/dist/stream-broker/{hostInit-BFH17kSk.mjs → hostInit-lj4kKHrb.mjs} +3 -3
  22. package/dist/stream-broker/index.js +7 -4
  23. package/dist/stream-broker/index.mjs +7 -4
  24. package/dist/stream-broker/remoteEntry.js +1 -1
  25. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-yeSHfpUy.js → MaskShapeCanvas-DI4BY7W2-BRQ5u_mo.js} +1 -1
  26. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-Df4WxM6N.js → MotionZonesSettings-NcxxQN8r-KbOg5nD9.js} +1 -1
  27. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-COHSiTGq.js → PrivacyMaskSettings-APgPLF7p-CKSPn3_D.js} +1 -1
  28. package/embed-dist/assets/index-CGdwTcwE.css +2 -0
  29. package/embed-dist/assets/{index-Ct9M2v5n.js → index-CbrEyYGW.js} +13 -13
  30. package/embed-dist/index.html +2 -2
  31. package/package.json +1 -1
  32. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B59GNAJq.mjs +0 -26
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-83qNzMSL.mjs +0 -26
  34. package/embed-dist/assets/index-4fJzjj4H.css +0 -2
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-Bz24uP1U.mjs
1
+ //#region ../types/dist/event-category-41fKf-q9.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -58,6 +58,26 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
58
58
  */
59
59
  EventCategory["AddonRetryScheduled"] = "addon.retry-scheduled";
60
60
  /**
61
+ * A liveness invariant of this node is false — it has no devices, every
62
+ * camera is offline, or a camera that was recording has stopped producing
63
+ * segments. Emitted by the `liveness-monitor` builtin, once per fault (the
64
+ * `findingId` is stable across ticks), only after its boot grace period.
65
+ * AlertCenter raises a persistent operator-visible alert.
66
+ *
67
+ * It exists because on 2026-08-03 the hub ran four hours with zero devices
68
+ * and zero recordings while every surface stayed quiet.
69
+ *
70
+ * Payload: `{ findingId, severity, title, message, deviceId? }`.
71
+ */
72
+ EventCategory["SystemLivenessFailed"] = "system.liveness-failed";
73
+ /**
74
+ * A previously reported liveness fault is true again. AlertCenter dismisses
75
+ * the matching `SystemLivenessFailed` alert.
76
+ *
77
+ * Payload: `{ findingId }`.
78
+ */
79
+ EventCategory["SystemLivenessRecovered"] = "system.liveness-recovered";
80
+ /**
61
81
  * Monitor is attempting to reload a failed addon NOW. UI uses this
62
82
  * to show a spinner during the retry attempt. Same transient nature
63
83
  * as AddonRetryScheduled.
@@ -9646,7 +9666,68 @@ var NcZoneConditionSchema = object({
9646
9666
  * The P1 condition set — a flat AND of groups; absent group = pass;
9647
9667
  * membership lists are OR within the list (spec §2.3).
9648
9668
  */
9669
+ /**
9670
+ * What a rule may actuate.
9671
+ *
9672
+ * **No hand-maintained allowlist** (operator decision, and the right one — a
9673
+ * written list of methods is a third parallel map to keep aligned, and this
9674
+ * repo has paid for those). The boundary instead comes from a property the
9675
+ * capabilities already carry: an action may target only a **device-scoped**
9676
+ * capability method.
9677
+ *
9678
+ * That is not decoration. A rule can be authored by a NON-ADMIN — personal
9679
+ * rules are a supported flow — and the executor runs with the addon's
9680
+ * privileges, so an unbounded action is an arbitrary RPC channel with a
9681
+ * privilege escalation attached. Restricting to device scope excludes the
9682
+ * system caps (`device-manager.removeDevice` and friends) by construction,
9683
+ * costs nothing to maintain, and cannot rot: a cap that stops being
9684
+ * device-scoped stops being actuatable in the same change.
9685
+ *
9686
+ * The executor enforces it; {@link NcRuleActionSchema} carries the intent.
9687
+ */
9688
+ /**
9689
+ * One step of a sequence.
9690
+ *
9691
+ * `wait` is a first-class step rather than a property of the next action: it is
9692
+ * what makes a sequence a SEQUENCE and not a list — "unlock, wait 5s, open"
9693
+ * cannot be expressed otherwise.
9694
+ */
9695
+ var NcRuleActionSchema = discriminatedUnion("kind", [object({
9696
+ kind: literal("wait"),
9697
+ seconds: number().min(0).max(300)
9698
+ }), object({
9699
+ kind: literal("cap"),
9700
+ deviceId: number().int(),
9701
+ /** Capability name, e.g. `alarm-panel`. */
9702
+ cap: string().min(1),
9703
+ /** Method on it. The executor refuses a non-device-scoped cap. */
9704
+ method: string().min(1),
9705
+ /** Method arguments, minus `deviceId` (the executor injects it). */
9706
+ args: record(string(), unknown()).optional()
9707
+ })]);
9708
+ /**
9709
+ * Sequences a rule runs, by hook point.
9710
+ *
9711
+ * ONLY `onTrigger` is here, deliberately. The reference also has activation /
9712
+ * deactivation / reset / post-generation hooks, and they are wanted — but this
9713
+ * repo's expensive failure mode is declaring a surface nothing produces, so a
9714
+ * hook appears here in the same change that produces its edge, never before.
9715
+ */
9716
+ var NcRuleActionsSchema = object({
9717
+ /** Runs when the rule MATCHES. */
9718
+ onTrigger: array(object({
9719
+ name: string().min(1).max(120),
9720
+ enabled: boolean(),
9721
+ minDelaySec: number().int().min(0).max(86400).optional(),
9722
+ actions: array(NcRuleActionSchema).min(1)
9723
+ })).optional() });
9649
9724
  var NcConditionsSchema = object({
9725
+ /** Gate on ANOTHER device's current state (the alarm armed, a switch on). */
9726
+ deviceState: object({
9727
+ deviceId: number().int(),
9728
+ /** Any of these matches. */
9729
+ states: array(string().min(1)).min(1)
9730
+ }).optional(),
9650
9731
  /** Device scope — absent = all devices. */
9651
9732
  devices: array(number()).optional(),
9652
9733
  /** Detector class names (any overlap with the record's class set). */
@@ -9847,6 +9928,14 @@ var NcMediaPolicySchema = object({
9847
9928
  clipPreRollSec: number().int().min(0).max(30).optional(),
9848
9929
  clipPostRollSec: number().int().min(0).max(30).optional(),
9849
9930
  /**
9931
+ * Playback rate of the attached gif / clip. Absent = 2x.
9932
+ *
9933
+ * A notification clip is GLANCED at on a lock screen, not watched: at real
9934
+ * time an eight-second passage is eight seconds of the recipient's attention
9935
+ * and twice the bytes. 1 is real time for the operator who wants it.
9936
+ */
9937
+ clipSpeed: number().min(1).max(8).optional(),
9938
+ /**
9850
9939
  * Which stream profile the footage is cut from. Absent = the CHEAPEST
9851
9940
  * assigned profile: a notification is watched on a phone, so the 4K
9852
9941
  * rendition would burn CPU to produce a file the client downscales anyway.
@@ -9918,7 +10007,30 @@ var NcRuleInputSchema = object({
9918
10007
  * behaviour, visible to all, read-only in the viewer). Present = personal
9919
10008
  * rule owned by this userId. Server-stamped; never trusted from a client.
9920
10009
  */
9921
- ownerUserId: string().optional()
10010
+ ownerUserId: string().optional(),
10011
+ /**
10012
+ * May a non-admin snooze this rule for EVERYONE, not just themselves?
10013
+ *
10014
+ * A snooze is personal by default — it silences the person who set it. This
10015
+ * opts THIS rule into the "the gardener is here all afternoon" case, where
10016
+ * silencing the camera for the whole household is legitimate. It silences
10017
+ * other people, so it is off unless a rule deliberately allows it.
10018
+ *
10019
+ * `.optional()`, deliberately NOT `.default()`: a Zod default does not run on
10020
+ * the addon cap path (three production failures in one day), so absent is
10021
+ * read as `false` by {@link canSetGlobal} in the engine. Admins are not bound
10022
+ * by this flag — see the scope rules on that function.
10023
+ */
10024
+ snoozeAllowGlobal: boolean().optional(),
10025
+ /**
10026
+ * Devices this rule ACTUATES — arm the alarm, open a gate, turn on a light.
10027
+ *
10028
+ * This is what makes the rule set the alarm's trigger set without the alarm
10029
+ * being a special case: arming is
10030
+ * `{ cap: 'alarm-panel', method: 'arm', args: { mode: 'away' } }`, the same
10031
+ * shape as every other actuation.
10032
+ */
10033
+ actions: NcRuleActionsSchema.optional()
9922
10034
  });
9923
10035
  /**
9924
10036
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -9989,7 +10101,8 @@ var NcConditionDescriptorSchema = object({
9989
10101
  "packagePhase",
9990
10102
  "crossingSelect",
9991
10103
  "polygonDraw",
9992
- "occupancy"
10104
+ "occupancy",
10105
+ "deviceState"
9993
10106
  ]),
9994
10107
  operator: _enum([
9995
10108
  "in",
@@ -10003,7 +10116,28 @@ var NcConditionDescriptorSchema = object({
10003
10116
  /** Which delivery kinds the condition applies to. */
10004
10117
  appliesTo: array(NcDeliverySchema),
10005
10118
  phase: string(),
10006
- description: string().optional()
10119
+ description: string().optional(),
10120
+ /**
10121
+ * The CHOICES for a single-choice widget (`sourceSelect`, `crossingSelect`,
10122
+ * `packagePhase`, …), served with the descriptor.
10123
+ *
10124
+ * Before this the descriptor said which widget to render and not what to put
10125
+ * in it, so every option list lived in three places: this file's enums, the
10126
+ * admin's `NC_*_OPTIONS` and the viewer's `NC_*_VALUES`. That triple mirror
10127
+ * is the drift that emptied the viewer's rule editor on 2026-08-04 — the app
10128
+ * mirrors the cap by hand, so it is only ever as current as its last build.
10129
+ *
10130
+ * With the options on the wire, a condition of an EXISTING `valueType` costs
10131
+ * zero client changes. Clients keep a local fallback for an older hub that
10132
+ * does not send them; absent here is "use your own list", not "no choices".
10133
+ */
10134
+ options: array(object({
10135
+ /** Written to the rule verbatim. `''` means the ABSENT state. */
10136
+ value: string(),
10137
+ label: string(),
10138
+ /** What THIS choice matches — shown one at a time, under the control. */
10139
+ hint: string().optional()
10140
+ })).readonly().optional()
10007
10141
  });
10008
10142
  /**
10009
10143
  * The delivery lifecycle status of a history row — a straight read of the
@@ -10088,6 +10222,74 @@ var NcHistoryFilterSchema = object({
10088
10222
  until: number().optional(),
10089
10223
  limit: number().int().min(1).max(500).default(100)
10090
10224
  });
10225
+ /**
10226
+ * What a snooze covers. Broader scopes win when several overlap, so one window
10227
+ * leaves ONE digest rather than a rule snooze and a whole-feed snooze both
10228
+ * summarising the same silence.
10229
+ */
10230
+ var NcSnoozeScopeSchema = _enum([
10231
+ "rule",
10232
+ "device",
10233
+ "all"
10234
+ ]);
10235
+ /**
10236
+ * Client-authored snooze. The server stamps `userId`, `startedAt` and
10237
+ * `expiresAt` — a DURATION is sent rather than an instant so a client with a
10238
+ * skewed clock cannot author a window that is already over, or never ends.
10239
+ */
10240
+ var NcSnoozeInputSchema = object({
10241
+ scope: NcSnoozeScopeSchema,
10242
+ /** Required when `scope: 'rule'` — a scoped snooze with no id matches
10243
+ * NOTHING rather than degrading to "everything". */
10244
+ ruleId: string().optional(),
10245
+ /** Required when `scope: 'device'`. */
10246
+ deviceId: number().int().optional(),
10247
+ durationMinutes: number().int().min(1).max(1440),
10248
+ /**
10249
+ * Silence this for EVERY recipient, not just the caller. Permission is
10250
+ * checked server-side (the rule's `snoozeAllowGlobal`, or admin for the
10251
+ * broader scopes). Absent = personal.
10252
+ */
10253
+ global: boolean().optional(),
10254
+ /**
10255
+ * Deliver a summary of what was suppressed when the window ends. Absent =
10256
+ * ON: someone silencing a nuisance camera wants it off, someone silencing a
10257
+ * SECURITY camera wants to know what they missed, and choosing "off" for
10258
+ * everybody is how a snooze becomes an outage. Resolved to a concrete
10259
+ * boolean by the server at create time — never left to a Zod default, which
10260
+ * does not run on the addon cap path.
10261
+ */
10262
+ summary: boolean().optional()
10263
+ });
10264
+ /** A persisted snooze window. */
10265
+ var NcSnoozeSchema = object({
10266
+ id: string(),
10267
+ /** Who set it. Also who it silences, unless `global`. */
10268
+ userId: string(),
10269
+ scope: NcSnoozeScopeSchema,
10270
+ ruleId: string().optional(),
10271
+ deviceId: number().int().optional(),
10272
+ startedAt: number(),
10273
+ /** Exclusive: at exactly this instant the snooze is over. Expiry is a
10274
+ * COMPARISON, not a job — no sweeper can leave the operator silenced. */
10275
+ expiresAt: number(),
10276
+ global: boolean(),
10277
+ summary: boolean(),
10278
+ /** When the end-of-window digest went out. Absent = not sent (yet, or the
10279
+ * window has not closed, or `summary` is false). */
10280
+ digestSentAt: number().optional()
10281
+ });
10282
+ object({
10283
+ snoozeId: string(),
10284
+ targetId: string(),
10285
+ ruleId: string(),
10286
+ ruleName: string(),
10287
+ deviceId: number().int(),
10288
+ /** How many notifications this snooze hid for that pair. */
10289
+ count: number().int(),
10290
+ firstAt: number(),
10291
+ lastAt: number()
10292
+ });
10091
10293
  method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), method(object({ ruleId: string() }), object({ rule: NcRuleSchema.nullable() }), { auth: "admin" }), method(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
10092
10294
  kind: "mutation",
10093
10295
  auth: "admin",
@@ -10117,7 +10319,13 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
10117
10319
  }), method(object({}), object({
10118
10320
  catalog: array(NcConditionDescriptorSchema),
10119
10321
  taxonomy: NcTaxonomySchema.optional()
10120
- })), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" });
10322
+ })), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }), method(object({}), object({ snoozes: array(NcSnoozeSchema) }), { caller: "required" }), method(object({ snooze: NcSnoozeInputSchema }), object({ snooze: NcSnoozeSchema }), {
10323
+ kind: "mutation",
10324
+ caller: "required"
10325
+ }), method(object({ snoozeId: string() }), object({ success: literal(true) }), {
10326
+ kind: "mutation",
10327
+ caller: "required"
10328
+ });
10121
10329
  /**
10122
10330
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
10123
10331
  *
@@ -10894,7 +11102,15 @@ var streamBrokerCapability = {
10894
11102
  format: _enum(["gif", "mp4"]).default("gif"),
10895
11103
  maxWidth: number().int().min(120).max(1920).default(480),
10896
11104
  /** GIF only — MP4 keeps the source cadence. */
10897
- fps: number().int().min(1).max(15).default(5)
11105
+ fps: number().int().min(1).max(15).default(5),
11106
+ /**
11107
+ * Playback rate. A notification clip is GLANCED at on a lock screen,
11108
+ * not watched, so 2x is the default: the recipient sees the whole
11109
+ * passage in half the time and the GIF is half the bytes. `1` is real
11110
+ * time. Applies to MP4 as well — the operator set a speed, not a GIF
11111
+ * speed.
11112
+ */
11113
+ speed: number().min(1).max(8).default(2)
10898
11114
  }), object({
10899
11115
  base64: string(),
10900
11116
  mime: string(),
@@ -16272,6 +16488,20 @@ var QueryFilterSchema = object({
16272
16488
  limit: number().optional(),
16273
16489
  offset: number().optional()
16274
16490
  });
16491
+ /**
16492
+ * The predicate half of a filter, for BULK MUTATIONS.
16493
+ *
16494
+ * Deliberately not `QueryFilterSchema`: `orderBy` / `limit` / `offset` have no
16495
+ * meaning for a statement that rewrites a set, and accepting them would invite
16496
+ * a caller to believe `limit` bounds the damage. Every field is optional here
16497
+ * only so the shape stays composable — the implementation REJECTS a filter
16498
+ * that compiles to no predicate, because that is the whole collection.
16499
+ */
16500
+ var MutationFilterSchema = object({
16501
+ where: record(string(), unknown()).optional(),
16502
+ whereIn: record(string(), array(unknown())).optional(),
16503
+ whereBetween: record(string(), tuple([unknown(), unknown()])).optional()
16504
+ });
16275
16505
  /** A single stored record: `{ id, data }`. */
16276
16506
  var SettingsRecordSchema = object({
16277
16507
  id: string(),
@@ -16297,7 +16527,18 @@ var CollectionColumnSchema = object({
16297
16527
  ]),
16298
16528
  primaryKey: boolean().optional(),
16299
16529
  notNull: boolean().optional(),
16300
- unique: boolean().optional()
16530
+ unique: boolean().optional(),
16531
+ /**
16532
+ * Column DEFAULT. Required for B2: the four `ensureTable` consumers declare
16533
+ * columns like `enabled INTEGER NOT NULL DEFAULT 1`, and without this the
16534
+ * collection surface simply cannot express their existing tables — which is
16535
+ * why they were still on the uncapped `table*` API.
16536
+ */
16537
+ defaultValue: union([
16538
+ string(),
16539
+ number(),
16540
+ boolean()
16541
+ ]).optional()
16301
16542
  });
16302
16543
  var CollectionIndexSchema = object({
16303
16544
  name: string(),
@@ -16331,6 +16572,15 @@ method(object({
16331
16572
  collection: string(),
16332
16573
  key: string()
16333
16574
  }), _void(), { kind: "mutation" }), method(object({
16575
+ namespace: string().optional(),
16576
+ collection: string(),
16577
+ filter: MutationFilterSchema
16578
+ }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
16579
+ namespace: string().optional(),
16580
+ collection: string(),
16581
+ filter: MutationFilterSchema,
16582
+ data: record(string(), unknown())
16583
+ }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
16334
16584
  namespace: string().optional(),
16335
16585
  collection: string(),
16336
16586
  filter: QueryFilterSchema.optional()
@@ -16397,6 +16647,15 @@ method(_void(), EngineInfoSchema), method(object({
16397
16647
  collection: string(),
16398
16648
  key: string()
16399
16649
  }), _void(), { kind: "mutation" }), method(object({
16650
+ namespace: string().optional(),
16651
+ collection: string(),
16652
+ filter: MutationFilterSchema
16653
+ }), object({ deleted: number().int() }), { kind: "mutation" }), method(object({
16654
+ namespace: string().optional(),
16655
+ collection: string(),
16656
+ filter: MutationFilterSchema,
16657
+ data: record(string(), unknown())
16658
+ }), object({ updated: number().int() }), { kind: "mutation" }), method(object({
16400
16659
  namespace: string().optional(),
16401
16660
  collection: string(),
16402
16661
  filter: QueryFilterSchema.optional()
@@ -17128,7 +17387,20 @@ method(object({
17128
17387
  }), _void(), {
17129
17388
  kind: "mutation",
17130
17389
  auth: "admin"
17131
- }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
17390
+ }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({
17391
+ addonId: string().optional(),
17392
+ /**
17393
+ * `slim` omits `config` (returned `{}`), `metadata` (null) and the
17394
+ * `sourceInfo` derived from config — and skips the per-device settings
17395
+ * read that produces them. Everything identifying a device (id, name,
17396
+ * type, online, features, isCamera, parent/link ids) is unchanged.
17397
+ * Do not use it for dispatch routing, which needs `sourceInfo`.
17398
+ */
17399
+ projection: _enum(["full", "slim"]).optional(),
17400
+ /** Return only camera devices. Filtering server-side instead of
17401
+ * shipping 293 rows to find 12. */
17402
+ isCamera: boolean().optional()
17403
+ }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
17132
17404
  mode: DeviceLinkModeSchema,
17133
17405
  devices: array(LinkedDeviceSchema)
17134
17406
  })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
@@ -18327,6 +18599,103 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18327
18599
  enabled: boolean()
18328
18600
  }), _void(), { kind: "mutation" });
18329
18601
  /**
18602
+ * core-blocks — user-authored TypeScript, stored in the kernel and executed in
18603
+ * its own process.
18604
+ *
18605
+ * Spec: `docs/superpowers/specs/2026-08-04-core-blocks-and-synthetic-devices-design.md`.
18606
+ *
18607
+ * The first use is **owning devices without being a device provider**: a block
18608
+ * declares devices under a system or custom integration and drives their state,
18609
+ * with the same `ctx` an addon gets. Automations come later; nothing here
18610
+ * models a trigger.
18611
+ *
18612
+ * **Stated plainly, because it does not change by being true:** a block has an
18613
+ * addon's powers — devices, storage, the event bus, `ctx.api`. It is a plugin
18614
+ * with no review step. What makes that survivable is not a sandbox, it is
18615
+ * PROCESS ISOLATION: one process per block, supervised by `CrashSupervisor`,
18616
+ * so a block that throws or never returns is marked `failed` and visible
18617
+ * instead of taking the hub with it (D6). Every method here is admin-only, and
18618
+ * must stay so.
18619
+ */
18620
+ /** Where a block runs. The operator chooses — a block driving a device on an
18621
+ * agent is the reason placement is not fixed to the hub. */
18622
+ var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
18623
+ /** What a block's process is doing. Mirrors the addon runner's own lifecycle so
18624
+ * a failing block reads the same way a failing addon does. */
18625
+ var CoreBlockStatusSchema = _enum([
18626
+ "stopped",
18627
+ "starting",
18628
+ "running",
18629
+ "failed"
18630
+ ]);
18631
+ /** Client-authored fields. */
18632
+ var CoreBlockInputSchema = object({
18633
+ name: string().min(1).max(120),
18634
+ /** TypeScript source. Compiled server-side before it is ever stored — a
18635
+ * block that does not compile is a fork failure the operator would meet
18636
+ * minutes later, in a log, instead of in the editor. */
18637
+ code: string().max(2e5),
18638
+ enabled: boolean(),
18639
+ placement: CoreBlockPlacementSchema,
18640
+ /**
18641
+ * Integration the block's devices hang from. Absent = the system integration
18642
+ * blocks share. A block may declare its own instead.
18643
+ */
18644
+ integrationId: string().optional()
18645
+ });
18646
+ /** A stored block. */
18647
+ var CoreBlockSchema = CoreBlockInputSchema.extend({
18648
+ id: string(),
18649
+ createdAt: number(),
18650
+ updatedAt: number(),
18651
+ /** Server-stamped author. */
18652
+ createdBy: string(),
18653
+ status: CoreBlockStatusSchema,
18654
+ /**
18655
+ * Why the block is not running, when it is not. The operator's ONLY window
18656
+ * into a block that failed at load — a block that is silently absent is the
18657
+ * failure mode this whole feature has to avoid.
18658
+ */
18659
+ lastError: string().optional(),
18660
+ /** Ms epoch of the last state change. */
18661
+ lastChangedAt: number()
18662
+ });
18663
+ /** What a compile attempt produced. */
18664
+ var CoreBlockCompileResultSchema = object({
18665
+ ok: boolean(),
18666
+ /** Present when `ok` is false — the first error, in the author's words. */
18667
+ error: string().optional(),
18668
+ line: number().optional(),
18669
+ column: number().optional()
18670
+ });
18671
+ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }), method(object({ blockId: string() }), object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }), method(object({ block: CoreBlockInputSchema }), object({ block: CoreBlockSchema }), {
18672
+ kind: "mutation",
18673
+ auth: "admin",
18674
+ caller: "required"
18675
+ }), method(object({
18676
+ blockId: string(),
18677
+ block: CoreBlockInputSchema.partial()
18678
+ }), object({ block: CoreBlockSchema }), {
18679
+ kind: "mutation",
18680
+ auth: "admin",
18681
+ caller: "required"
18682
+ }), method(object({ blockId: string() }), object({ success: literal(true) }), {
18683
+ kind: "mutation",
18684
+ auth: "admin"
18685
+ }), method(object({
18686
+ blockId: string(),
18687
+ enabled: boolean()
18688
+ }), object({ block: CoreBlockSchema }), {
18689
+ kind: "mutation",
18690
+ auth: "admin"
18691
+ }), method(object({ code: string() }), CoreBlockCompileResultSchema, {
18692
+ kind: "mutation",
18693
+ auth: "admin"
18694
+ }), method(object({}), object({ libs: array(object({
18695
+ filePath: string(),
18696
+ content: string()
18697
+ })) }), { auth: "admin" });
18698
+ /**
18330
18699
  * Zod schemas for persisted record types.
18331
18700
  *
18332
18701
  * These schemas serve as the single source of truth for types that are
@@ -18573,6 +18942,11 @@ var EventKindDescriptorSchema = object({
18573
18942
  deviceId: number()
18574
18943
  })
18575
18944
  });
18945
+ /** One camera's event vocabulary, as returned by `listEventKindsBatch`. */
18946
+ var EventKindsForDeviceSchema = object({
18947
+ deviceId: number(),
18948
+ kinds: array(EventKindDescriptorSchema).readonly()
18949
+ });
18576
18950
  var SensorEventSchema = object({
18577
18951
  id: string(),
18578
18952
  /** The CAMERA the event is attributed to (a sensor linked to N cameras
@@ -18829,6 +19203,19 @@ var MediaFileSchema = object({
18829
19203
  sizeBytes: number(),
18830
19204
  timestamp: number()
18831
19205
  });
19206
+ /**
19207
+ * One media row WITHOUT its bytes.
19208
+ *
19209
+ * A track's media is 5-8 MB of base64 (measured: 7.67 MB across 23 files for a
19210
+ * 140 s track), and a client that renders tiles from the media data plane needs
19211
+ * to know only WHAT EXISTS — the bytes then arrive per tile, lazily, over HTTP
19212
+ * with an immutable cache, instead of all at once inside a tRPC response that
19213
+ * blocks the whole view.
19214
+ *
19215
+ * `sizeBytes` is carried because it is what lets a client decide between the
19216
+ * stored blob and a `?variant=thumb` rendering without fetching either.
19217
+ */
19218
+ var MediaFileInfoSchema = MediaFileSchema.omit({ base64: true });
18832
19219
  var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
18833
19220
  var MAX_EVENT_QUERY_LIMIT = 5e3;
18834
19221
  var DeviceEventQueryInput = object({
@@ -18978,7 +19365,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18978
19365
  }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
18979
19366
  kind: "mutation",
18980
19367
  auth: "admin"
18981
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
19368
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
18982
19369
  deviceId: number(),
18983
19370
  since: number().optional(),
18984
19371
  until: number().optional(),
@@ -19052,7 +19439,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19052
19439
  }), array(MediaFileSchema).readonly()), method(object({
19053
19440
  trackId: string(),
19054
19441
  kinds: array(MediaFileKindEnum).optional()
19055
- }), array(MediaFileSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), object({
19442
+ }), array(MediaFileSchema).readonly()), method(object({ trackId: string() }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), object({
19056
19443
  deviceId: number(),
19057
19444
  timestamp: number(),
19058
19445
  frameWidth: number(),
@@ -23833,6 +24220,54 @@ Object.freeze({
23833
24220
  addonId: null,
23834
24221
  access: "create"
23835
24222
  },
24223
+ "coreBlocks.compile": {
24224
+ capName: "core-blocks",
24225
+ capScope: "system",
24226
+ addonId: null,
24227
+ access: "create"
24228
+ },
24229
+ "coreBlocks.create": {
24230
+ capName: "core-blocks",
24231
+ capScope: "system",
24232
+ addonId: null,
24233
+ access: "create"
24234
+ },
24235
+ "coreBlocks.delete": {
24236
+ capName: "core-blocks",
24237
+ capScope: "system",
24238
+ addonId: null,
24239
+ access: "delete"
24240
+ },
24241
+ "coreBlocks.get": {
24242
+ capName: "core-blocks",
24243
+ capScope: "system",
24244
+ addonId: null,
24245
+ access: "view"
24246
+ },
24247
+ "coreBlocks.getTypeDefs": {
24248
+ capName: "core-blocks",
24249
+ capScope: "system",
24250
+ addonId: null,
24251
+ access: "view"
24252
+ },
24253
+ "coreBlocks.list": {
24254
+ capName: "core-blocks",
24255
+ capScope: "system",
24256
+ addonId: null,
24257
+ access: "view"
24258
+ },
24259
+ "coreBlocks.setEnabled": {
24260
+ capName: "core-blocks",
24261
+ capScope: "system",
24262
+ addonId: null,
24263
+ access: "create"
24264
+ },
24265
+ "coreBlocks.update": {
24266
+ capName: "core-blocks",
24267
+ capScope: "system",
24268
+ addonId: null,
24269
+ access: "create"
24270
+ },
23836
24271
  "cover.close": {
23837
24272
  capName: "cover",
23838
24273
  capScope: "device",
@@ -23887,6 +24322,12 @@ Object.freeze({
23887
24322
  addonId: null,
23888
24323
  access: "delete"
23889
24324
  },
24325
+ "dataStoreProvider.deleteWhere": {
24326
+ capName: "data-store-provider",
24327
+ capScope: "system",
24328
+ addonId: null,
24329
+ access: "delete"
24330
+ },
23890
24331
  "dataStoreProvider.get": {
23891
24332
  capName: "data-store-provider",
23892
24333
  capScope: "system",
@@ -23935,6 +24376,12 @@ Object.freeze({
23935
24376
  addonId: null,
23936
24377
  access: "create"
23937
24378
  },
24379
+ "dataStoreProvider.updateWhere": {
24380
+ capName: "data-store-provider",
24381
+ capScope: "system",
24382
+ addonId: null,
24383
+ access: "create"
24384
+ },
23938
24385
  "dayNight.getOptions": {
23939
24386
  capName: "day-night",
23940
24387
  capScope: "device",
@@ -25729,12 +26176,24 @@ Object.freeze({
25729
26176
  addonId: null,
25730
26177
  access: "create"
25731
26178
  },
26179
+ "notificationRules.cancelSnooze": {
26180
+ capName: "notification-rules",
26181
+ capScope: "system",
26182
+ addonId: null,
26183
+ access: "create"
26184
+ },
25732
26185
  "notificationRules.createRule": {
25733
26186
  capName: "notification-rules",
25734
26187
  capScope: "system",
25735
26188
  addonId: null,
25736
26189
  access: "create"
25737
26190
  },
26191
+ "notificationRules.createSnooze": {
26192
+ capName: "notification-rules",
26193
+ capScope: "system",
26194
+ addonId: null,
26195
+ access: "create"
26196
+ },
25738
26197
  "notificationRules.deleteRule": {
25739
26198
  capName: "notification-rules",
25740
26199
  capScope: "system",
@@ -25765,6 +26224,12 @@ Object.freeze({
25765
26224
  addonId: null,
25766
26225
  access: "view"
25767
26226
  },
26227
+ "notificationRules.listSnoozes": {
26228
+ capName: "notification-rules",
26229
+ capScope: "system",
26230
+ addonId: null,
26231
+ access: "view"
26232
+ },
25768
26233
  "notificationRules.setRuleEnabled": {
25769
26234
  capName: "notification-rules",
25770
26235
  capScope: "system",
@@ -25969,6 +26434,12 @@ Object.freeze({
25969
26434
  addonId: null,
25970
26435
  access: "view"
25971
26436
  },
26437
+ "pipelineAnalytics.listEventKindsBatch": {
26438
+ capName: "pipeline-analytics",
26439
+ capScope: "device",
26440
+ addonId: null,
26441
+ access: "view"
26442
+ },
25972
26443
  "pipelineAnalytics.listOpsLog": {
25973
26444
  capName: "pipeline-analytics",
25974
26445
  capScope: "device",
@@ -25981,6 +26452,12 @@ Object.freeze({
25981
26452
  addonId: null,
25982
26453
  access: "view"
25983
26454
  },
26455
+ "pipelineAnalytics.listTrackMedia": {
26456
+ capName: "pipeline-analytics",
26457
+ capScope: "device",
26458
+ addonId: null,
26459
+ access: "view"
26460
+ },
25984
26461
  "pipelineAnalytics.listTracks": {
25985
26462
  capName: "pipeline-analytics",
25986
26463
  capScope: "device",
@@ -27013,6 +27490,12 @@ Object.freeze({
27013
27490
  addonId: null,
27014
27491
  access: "delete"
27015
27492
  },
27493
+ "settingsStore.deleteWhere": {
27494
+ capName: "settings-store",
27495
+ capScope: "system",
27496
+ addonId: null,
27497
+ access: "delete"
27498
+ },
27016
27499
  "settingsStore.get": {
27017
27500
  capName: "settings-store",
27018
27501
  capScope: "system",
@@ -27055,6 +27538,12 @@ Object.freeze({
27055
27538
  addonId: null,
27056
27539
  access: "create"
27057
27540
  },
27541
+ "settingsStore.updateWhere": {
27542
+ capName: "settings-store",
27543
+ capScope: "system",
27544
+ addonId: null,
27545
+ access: "create"
27546
+ },
27058
27547
  "smtpProvider.getStatus": {
27059
27548
  capName: "smtp-provider",
27060
27549
  capScope: "system",