@camstack/types 1.2.281 → 1.2.283

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7419,6 +7419,119 @@ var authProviderCapability = {
7419
7419
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
7420
7420
  mount: { kind: "skip" }
7421
7421
  };
7422
+ //#endregion
7423
+ //#region src/capabilities/database-snapshot.cap.ts
7424
+ /**
7425
+ * The suffix of a verified snapshot, written next to the live database it
7426
+ * copies: `<db>.backup-snapshot`. A restore promotes it back over `<db>`
7427
+ * (`server/backend/src/sqlite-restore.ts` spells the same string — the
7428
+ * launcher stays free of `@camstack/*` runtime imports — and a spec pins the
7429
+ * two together).
7430
+ */
7431
+ var DATABASE_SNAPSHOT_SUFFIX = ".backup-snapshot";
7432
+ /**
7433
+ * The suffix of a copy still being written or verified. A file under this name
7434
+ * is never archived and never promoted: only a copy that passed every check is
7435
+ * renamed to {@link DATABASE_SNAPSHOT_SUFFIX}.
7436
+ */
7437
+ var DATABASE_SNAPSHOT_PARTIAL_SUFFIX = ".backup-snapshot-partial";
7438
+ /**
7439
+ * How long one snapshot may take end to end: the pinned copy of the whole
7440
+ * database plus `PRAGMA integrity_check` over the copy, on the hub's slowest
7441
+ * disk. ~800 MB at a pessimistic 10 MB/s is under 3 minutes; the bound is
7442
+ * generous because a timeout fails the whole backup run.
7443
+ */
7444
+ var DATABASE_SNAPSHOT_TIMEOUT_MS = 30 * 6e4;
7445
+ /**
7446
+ * The databases an owner snapshots — declared by the OWNER, so a caller never
7447
+ * guesses which file is live from what sits beside it (a cleanly closed
7448
+ * database has no sidecars and is just as owned). Paths are absolute on the
7449
+ * owner's host.
7450
+ */
7451
+ var DatabaseSnapshotTargetsSchema = zod.z.object({ databases: zod.z.array(zod.z.object({ livePath: zod.z.string() })) });
7452
+ /** One b-tree table of the snapshot and the rows it holds. */
7453
+ var DatabaseSnapshotTableSchema = zod.z.object({
7454
+ name: zod.z.string(),
7455
+ rows: zod.z.number().int().nonnegative()
7456
+ });
7457
+ /**
7458
+ * What the owner wrote. Every path is ABSOLUTE on the owner's host — the
7459
+ * caller pins the call to its own node, so it can read the file; a caller
7460
+ * that finds the path outside its own data root refuses it rather than
7461
+ * archiving something it cannot place.
7462
+ */
7463
+ var DatabaseSnapshotResultSchema = zod.z.object({
7464
+ /** The live database the snapshot copies. Never to be copied as a file. */
7465
+ livePath: zod.z.string(),
7466
+ /** The verified copy: `<livePath>` + {@link DATABASE_SNAPSHOT_SUFFIX}. */
7467
+ snapshotPath: zod.z.string(),
7468
+ sizeBytes: zod.z.number().int().nonnegative(),
7469
+ pageCount: zod.z.number().int().nonnegative(),
7470
+ pageSize: zod.z.number().int().positive(),
7471
+ /**
7472
+ * Every b-tree table with its row count. Read inside the SAME read
7473
+ * transaction the copy was taken from, and found EQUAL on the copy — so
7474
+ * this is the content of the snapshot, not an estimate of the source.
7475
+ */
7476
+ tables: zod.z.array(DatabaseSnapshotTableSchema),
7477
+ /** Wall time of the pinned copy (row counts included). */
7478
+ copyMs: zod.z.number().nonnegative(),
7479
+ /** Wall time of the checks on the copy (`integrity_check`, row counts). */
7480
+ verifyMs: zod.z.number().nonnegative(),
7481
+ /** When the pinned read transaction began (ms epoch) — the snapshot's instant. */
7482
+ takenAt: zod.z.number()
7483
+ });
7484
+ /**
7485
+ * A snapshot as an ARCHIVE records it (`ArchiveManifest.sqliteSnapshots`):
7486
+ * the same facts, with both paths relative to the archive root (the node's
7487
+ * data dir), because an archive outlives the host that made it.
7488
+ */
7489
+ var ArchiveSqliteSnapshotSchema = DatabaseSnapshotResultSchema.extend({
7490
+ /** Archive-relative path of the live database the archive does NOT carry. */
7491
+ livePath: zod.z.string(),
7492
+ /** Archive-relative path of the verified copy it carries in its place. */
7493
+ snapshotPath: zod.z.string()
7494
+ });
7495
+ /**
7496
+ * database-snapshot — the OWNER of a live SQLite database writes a consistent,
7497
+ * verified copy of it (D693).
7498
+ *
7499
+ * A live database cannot be copied as files: three files written by a live
7500
+ * process cannot be read at one instant from outside it, and a tar of the
7501
+ * `.db` / `-wal` / `-shm` trio was measured torn in 6/6 archives (D679). Nor may
7502
+ * another process open it (D679 rule 2). So the process that owns the
7503
+ * connection writes the copy — through its own connection, on a thread,
7504
+ * pinned to one read transaction — and checks it before handing it out.
7505
+ *
7506
+ * Hub-only and internal: `sqlite-settings` is the registrant, and its consumer
7507
+ * is `backup-orchestrator`, which calls it pinned to its own node so the path
7508
+ * it gets back is on its own host. `auth: 'admin'` explicitly — `internal`
7509
+ * does not gate the mount (see `data-store-provider`).
7510
+ */
7511
+ var databaseSnapshotCapability = {
7512
+ name: "database-snapshot",
7513
+ scope: "system",
7514
+ mode: "singleton",
7515
+ internal: true,
7516
+ methods: {
7517
+ /**
7518
+ * Which databases this owner snapshots. Answered from memory — no file is
7519
+ * touched — so a backup can ask it before deciding anything.
7520
+ */
7521
+ listDatabases: require_sleep.method(zod.z.object({}), DatabaseSnapshotTargetsSchema, { auth: "admin" }),
7522
+ /**
7523
+ * Write `<db>.backup-snapshot` and return what it holds. Throws — and
7524
+ * leaves no file under the final name — when the copy fails
7525
+ * `integrity_check` or its row counts differ from the pinned source's.
7526
+ * A second call while one is running joins it.
7527
+ */
7528
+ writeSnapshot: require_sleep.method(zod.z.object({}), DatabaseSnapshotResultSchema, {
7529
+ kind: "mutation",
7530
+ auth: "admin",
7531
+ timeoutMs: DATABASE_SNAPSHOT_TIMEOUT_MS
7532
+ })
7533
+ }
7534
+ };
7422
7535
  /**
7423
7536
  * Orchestrator-side destination metadata. The orchestrator computes
7424
7537
  * `id = <addonId>:<subId>` from its provider lookup so consumers
@@ -7530,7 +7643,12 @@ var ArchiveManifestSchema = zod.z.object({
7530
7643
  locations: zod.z.array(zod.z.string()),
7531
7644
  entries: zod.z.array(ArchiveEntrySchema),
7532
7645
  totalBytes: zod.z.number(),
7533
- totalFiles: zod.z.number()
7646
+ totalFiles: zod.z.number(),
7647
+ /**
7648
+ * Live SQLite databases this archive carries as their OWNER's verified
7649
+ * snapshot instead of as files (D693). Absent on archives made before.
7650
+ */
7651
+ sqliteSnapshots: zod.z.array(ArchiveSqliteSnapshotSchema).optional()
7534
7652
  });
7535
7653
  var LocationStatSchema = zod.z.object({
7536
7654
  name: zod.z.string(),
@@ -9920,6 +10038,79 @@ var CompositionBlockStateSchema = zod.z.object({
9920
10038
  fields: zod.z.array(CompositionFieldStateSchema)
9921
10039
  });
9922
10040
  //#endregion
10041
+ //#region src/capabilities/composer.cap.ts
10042
+ /**
10043
+ * composer — runs every DECLARATIVE composition (D659).
10044
+ *
10045
+ * Internal and admin-only: its one caller is `core-blocks`' supervisor, which
10046
+ * sends the WHOLE set of composition blocks on every converge (idempotent),
10047
+ * and reads their state for the API. Nothing else talks to it.
10048
+ */
10049
+ /** The composer's runner id, `resolveRunnerId(decl, 'composer')`; pinned by `composer-manifest.spec.ts`. */
10050
+ var COMPOSER_RUNNER_ID = require_composition.COMPOSER_ADDON_ID;
10051
+ var ComposerBlockSchema = zod.z.object({
10052
+ id: zod.z.string().min(1),
10053
+ name: zod.z.string().min(1).max(120),
10054
+ enabled: zod.z.boolean(),
10055
+ updatedAt: zod.z.number(),
10056
+ composition: require_composition.CompositionSchema
10057
+ });
10058
+ /**
10059
+ * A stored composition row that no longer PARSES — a schema a release
10060
+ * tightened, a row written by a newer build. Sent by id so the composer keeps
10061
+ * its device as a placeholder and reports the block `failed` naming the parse
10062
+ * error. Leaving it out would read, twice, exactly like a delete (D49).
10063
+ */
10064
+ var ComposerUnreadableBlockSchema = zod.z.object({
10065
+ id: zod.z.string().min(1),
10066
+ /** The row's stored name column; null when even that is unreadable (the device keeps the name it has). */
10067
+ name: zod.z.string().nullable(),
10068
+ /** The parse error, in the operator's words. */
10069
+ error: zod.z.string()
10070
+ });
10071
+ var ComposerApplyInputSchema = zod.z.object({
10072
+ /** The shared Blocks integration; null until `core-blocks` has reconciled it. */
10073
+ integrationId: zod.z.string().nullable(),
10074
+ /** False when the `core_blocks` read failed: then nothing may be withdrawn (D49). */
10075
+ storeLoaded: zod.z.boolean(),
10076
+ blocks: zod.z.array(ComposerBlockSchema),
10077
+ /** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
10078
+ restartBlockIds: zod.z.array(zod.z.string()),
10079
+ /** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
10080
+ unreadableBlocks: zod.z.array(ComposerUnreadableBlockSchema)
10081
+ });
10082
+ var ComposerBlockVerdictSchema = zod.z.object({
10083
+ blockId: zod.z.string(),
10084
+ status: CompositionRunStatusSchema,
10085
+ reason: zod.z.string().optional()
10086
+ });
10087
+ var ComposerApplyResultSchema = zod.z.object({
10088
+ blocks: zod.z.array(ComposerBlockVerdictSchema),
10089
+ /**
10090
+ * False when the composer declared and withdrew NOTHING (store not loaded,
10091
+ * integration unknown, its own rows unread or read empty once). An empty
10092
+ * apply the caller owes is paid off only by one the composer acted on (D49).
10093
+ */
10094
+ acted: zod.z.boolean()
10095
+ });
10096
+ var composerCapability = {
10097
+ name: "composer",
10098
+ scope: "system",
10099
+ mode: "singleton",
10100
+ internal: true,
10101
+ methods: {
10102
+ /**
10103
+ * Not `apply`: tRPC reserves `apply`, `call` and `then` as router keys, and
10104
+ * `router({})` throws on one — every cap router is built at boot.
10105
+ */
10106
+ applyBlocks: require_sleep.method(ComposerApplyInputSchema, ComposerApplyResultSchema, {
10107
+ kind: "mutation",
10108
+ auth: "admin"
10109
+ }),
10110
+ getStates: require_sleep.method(zod.z.object({ blockIds: zod.z.array(zod.z.string()) }), zod.z.object({ states: zod.z.array(CompositionBlockStateSchema) }), { auth: "admin" })
10111
+ }
10112
+ };
10113
+ //#endregion
9923
10114
  //#region src/composition/plan-result.ts
9924
10115
  function problem(code, path, message) {
9925
10116
  return {
@@ -11168,79 +11359,6 @@ var coreBlocksCapability = {
11168
11359
  }
11169
11360
  };
11170
11361
  //#endregion
11171
- //#region src/capabilities/composer.cap.ts
11172
- /**
11173
- * composer — runs every DECLARATIVE composition (D659).
11174
- *
11175
- * Internal and admin-only: its one caller is `core-blocks`' supervisor, which
11176
- * sends the WHOLE set of composition blocks on every converge (idempotent),
11177
- * and reads their state for the API. Nothing else talks to it.
11178
- */
11179
- /** The composer's runner id, `resolveRunnerId(decl, 'composer')`; pinned by `composer-manifest.spec.ts`. */
11180
- var COMPOSER_RUNNER_ID = require_composition.COMPOSER_ADDON_ID;
11181
- var ComposerBlockSchema = zod.z.object({
11182
- id: zod.z.string().min(1),
11183
- name: zod.z.string().min(1).max(120),
11184
- enabled: zod.z.boolean(),
11185
- updatedAt: zod.z.number(),
11186
- composition: require_composition.CompositionSchema
11187
- });
11188
- /**
11189
- * A stored composition row that no longer PARSES — a schema a release
11190
- * tightened, a row written by a newer build. Sent by id so the composer keeps
11191
- * its device as a placeholder and reports the block `failed` naming the parse
11192
- * error. Leaving it out would read, twice, exactly like a delete (D49).
11193
- */
11194
- var ComposerUnreadableBlockSchema = zod.z.object({
11195
- id: zod.z.string().min(1),
11196
- /** The row's stored name column; null when even that is unreadable (the device keeps the name it has). */
11197
- name: zod.z.string().nullable(),
11198
- /** The parse error, in the operator's words. */
11199
- error: zod.z.string()
11200
- });
11201
- var ComposerApplyInputSchema = zod.z.object({
11202
- /** The shared Blocks integration; null until `core-blocks` has reconciled it. */
11203
- integrationId: zod.z.string().nullable(),
11204
- /** False when the `core_blocks` read failed: then nothing may be withdrawn (D49). */
11205
- storeLoaded: zod.z.boolean(),
11206
- blocks: zod.z.array(ComposerBlockSchema),
11207
- /** Operator restarts: rebuild these runtimes and re-resolve their sources. Stores nothing (D62). */
11208
- restartBlockIds: zod.z.array(zod.z.string()),
11209
- /** Composition rows that exist but do not parse: held, never withdrawn, reported failed. */
11210
- unreadableBlocks: zod.z.array(ComposerUnreadableBlockSchema)
11211
- });
11212
- var ComposerBlockVerdictSchema = zod.z.object({
11213
- blockId: zod.z.string(),
11214
- status: CompositionRunStatusSchema,
11215
- reason: zod.z.string().optional()
11216
- });
11217
- var ComposerApplyResultSchema = zod.z.object({
11218
- blocks: zod.z.array(ComposerBlockVerdictSchema),
11219
- /**
11220
- * False when the composer declared and withdrew NOTHING (store not loaded,
11221
- * integration unknown, its own rows unread or read empty once). An empty
11222
- * apply the caller owes is paid off only by one the composer acted on (D49).
11223
- */
11224
- acted: zod.z.boolean()
11225
- });
11226
- var composerCapability = {
11227
- name: "composer",
11228
- scope: "system",
11229
- mode: "singleton",
11230
- internal: true,
11231
- methods: {
11232
- /**
11233
- * Not `apply`: tRPC reserves `apply`, `call` and `then` as router keys, and
11234
- * `router({})` throws on one — every cap router is built at boot.
11235
- */
11236
- applyBlocks: require_sleep.method(ComposerApplyInputSchema, ComposerApplyResultSchema, {
11237
- kind: "mutation",
11238
- auth: "admin"
11239
- }),
11240
- getStates: require_sleep.method(zod.z.object({ blockIds: zod.z.array(zod.z.string()) }), zod.z.object({ states: zod.z.array(CompositionBlockStateSchema) }), { auth: "admin" })
11241
- }
11242
- };
11243
- //#endregion
11244
11362
  //#region src/capabilities/custom-model-registry.cap.ts
11245
11363
  /**
11246
11364
  * `custom-model-registry` — collection cap exposing operator-registered
@@ -14715,6 +14833,337 @@ var deviceManagerCapability = {
14715
14833
  }
14716
14834
  };
14717
14835
  //#endregion
14836
+ //#region src/capabilities/doorbell.cap.ts
14837
+ /**
14838
+ * Doorbell button cap. Two kinds of providers coexist behind this cap
14839
+ * name (same pattern as `snapshot`):
14840
+ *
14841
+ * - **Native** providers: registered per-device by device-driver
14842
+ * addons via `ctx.registerNativeCap` — either on a
14843
+ * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
14844
+ * or directly on the camera (Reolink registers at camera level).
14845
+ * Emits an `onPressed` event every time the firmware pushes a
14846
+ * ring; status tracks the last press and a pressCount since start
14847
+ * (diagnostic).
14848
+ *
14849
+ * - **Wrapper** provider: the `virtual-doorbell` system builtin
14850
+ * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
14851
+ * device (contact / switch / event-emitter …) into a doorbell for
14852
+ * a camera. `defaultActive: false` — the operator explicitly binds
14853
+ * it per camera in the device-bindings UI, then picks the source
14854
+ * device + trigger in the per-device settings.
14855
+ *
14856
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent
14857
+ * — subscribers listening at the camera level receive ring events
14858
+ * with `via[]` populated. No code on the parent needed.
14859
+ */
14860
+ var DoorbellStatusSchema = zod.z.object({
14861
+ /** Ms epoch of the last press. null = never observed since this provider started. */
14862
+ lastPressedAt: zod.z.number().nullable(),
14863
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
14864
+ pressCountSinceStart: zod.z.number()
14865
+ });
14866
+ var DoorbellPressEventSchema = zod.z.object({
14867
+ deviceId: zod.z.number(),
14868
+ timestamp: zod.z.number()
14869
+ });
14870
+ /**
14871
+ * The `doorbell-source` extension slot's editable value (D648): the camera's
14872
+ * virtual-doorbell trigger devices, exactly what the wrapper's
14873
+ * `doorbellSources` persists (as `{ deviceId }` records).
14874
+ */
14875
+ var DoorbellSourceSlotValueSchema = zod.z.object({ deviceIds: zod.z.array(zod.z.number().int().positive()) });
14876
+ /**
14877
+ * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
14878
+ * doorbell, owned by the `virtual-doorbell` wrapper over its
14879
+ * `doorbellSources` store (D648). A source rings when one of its
14880
+ * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
14881
+ * different authority (`deviceManager.setWrapperActive`, D62) — the slot
14882
+ * reports it, it never writes it.
14883
+ */
14884
+ var DOORBELL_SOURCE_SLOT = {
14885
+ id: "doorbell-source",
14886
+ label: "Doorbell trigger devices",
14887
+ description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
14888
+ shape: "association",
14889
+ hostDeviceTypes: [require_err_msg.DeviceType.Camera],
14890
+ sourceCaps: require_composition.SOURCE_CAPS,
14891
+ cardinality: "many",
14892
+ value: DoorbellSourceSlotValueSchema
14893
+ };
14894
+ var doorbellCapability = {
14895
+ name: "doorbell",
14896
+ scope: "device",
14897
+ deviceNative: true,
14898
+ mode: "singleton",
14899
+ kind: "wrapper",
14900
+ defaultActive: false,
14901
+ deviceTypes: [require_err_msg.DeviceType.Button, require_err_msg.DeviceType.Camera],
14902
+ extensionSlots: [DOORBELL_SOURCE_SLOT],
14903
+ methods: {},
14904
+ events: {
14905
+ /**
14906
+ * Fires once per physical press. Reolink delivers via Baichuan
14907
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
14908
+ * release/duration — it's a pulse.
14909
+ */
14910
+ onPressed: {
14911
+ data: DoorbellPressEventSchema,
14912
+ fromState: {
14913
+ field: "lastPressedAt",
14914
+ on: "advance"
14915
+ }
14916
+ } },
14917
+ status: {
14918
+ schema: DoorbellStatusSchema,
14919
+ kind: "push"
14920
+ },
14921
+ /**
14922
+ * Runtime-state slice — last press timestamp + lifetime press count.
14923
+ * Mirrored by the kernel and readable via
14924
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
14925
+ * without subscribing.
14926
+ */
14927
+ runtimeState: DoorbellStatusSchema,
14928
+ /**
14929
+ * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
14930
+ *
14931
+ * See `RuntimeStateDurability`. Enforced by
14932
+ * `scripts/check-runtime-state-durability.ts`.
14933
+ */
14934
+ durability: "restored"
14935
+ };
14936
+ //#endregion
14937
+ //#region src/generated/extension-slots.ts
14938
+ /**
14939
+ * AUTO-GENERATED by scripts/generate-extension-slots.ts — DO NOT EDIT.
14940
+ *
14941
+ * Every extension slot declared by a capability (`extensionSlots` in its
14942
+ * `*.cap.ts`, D648), folded into one typed table. Imports ONLY the declaring
14943
+ * caps' descriptors and value schemas — never the caps barrel — so
14944
+ * `device-extension.cap.ts` can import this module without a cycle.
14945
+ *
14946
+ * Coverage: 2 slot(s).
14947
+ */
14948
+ /** Every declared slot id, in table order. */
14949
+ var EXTENSION_SLOT_IDS = ["doorbell-source", "linked-devices"];
14950
+ var ExtensionSlotIdSchema = zod.z.enum(EXTENSION_SLOT_IDS);
14951
+ var EXTENSION_SLOTS = {
14952
+ "doorbell-source": {
14953
+ descriptor: DOORBELL_SOURCE_SLOT,
14954
+ declaringCap: "doorbell",
14955
+ hostDeviceTypes: [require_err_msg.DeviceType.Camera]
14956
+ },
14957
+ "linked-devices": {
14958
+ descriptor: LINKED_DEVICES_SLOT,
14959
+ declaringCap: "device-manager",
14960
+ hostDeviceTypes: [require_err_msg.DeviceType.Camera]
14961
+ }
14962
+ };
14963
+ /** A slot's editable value, discriminated on `slot`. */
14964
+ var ExtensionSlotValueSchema = zod.z.discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: zod.z.literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: zod.z.literal("linked-devices") })]);
14965
+ /** Every device type at least one slot is offered on — `device-extension`'s `deviceTypes`. */
14966
+ var EXTENSION_HOST_DEVICE_TYPES = [require_err_msg.DeviceType.Camera];
14967
+ //#endregion
14968
+ //#region src/capabilities/device-extension.cap.ts
14969
+ /**
14970
+ * `device-extension` — ONE place to see and author what a device is extended
14971
+ * with by OTHER devices (D648).
14972
+ *
14973
+ * **A contract, not a store.** Every slot (`linked-devices`, `doorbell-source`)
14974
+ * is declared by the cap that owns the function (`extensionSlots` in its
14975
+ * `*.cap.ts`, D4) and SERVED by the addon that already owns its store, over
14976
+ * that store and its existing write path. This cap persists nothing and has no config method (guarded by
14977
+ * `scripts/check-extension-slots.ts`): D62 applied to the whole feature, and
14978
+ * D3 — no shadow registry.
14979
+ *
14980
+ * **Shape.** A device-scoped wrapper COLLECTION, the D554 shape `videoclips`
14981
+ * uses: `resolveCapMount` gives it the `device-scoped` mount and
14982
+ * `requireDeviceCollection` dispatches it. Its providers are the slot owners
14983
+ * (device-manager, virtual-doorbell, …), and a device's sources are its
14984
+ * bindings (step 0 of `getBindings`, derived, persisted nowhere).
14985
+ *
14986
+ * - `listSources` — one row per provider, the D554 source-listing convention
14987
+ * that lets a scalar call be routed by the prefix of its `slotRef`.
14988
+ * - `listSlots` — fan-out, concatenated. A provider that throws becomes ONE
14989
+ * `unreachable` row naming it, never an absence (D554.4, D315): "no
14990
+ * extensions" is claimed only from an answer.
14991
+ * - `listCandidates` / `setSlot` — scalar, routed by `slotRef`
14992
+ * (`<source>:<slotId>`). An unclaimed ref is refused by name (D554.5).
14993
+ *
14994
+ * The slot's value travels as the generated discriminated union
14995
+ * (`ExtensionSlotValue`, keyed on `slot`), so a value under the wrong slot is
14996
+ * a schema error before it reaches any owner.
14997
+ *
14998
+ * **Associations only.** A slot LISTS other devices on its host. A host that
14999
+ * GAINS a capability from other devices is a composition (D663, amends D648:
15000
+ * the reserved `graft` shape, its `projects` and its `enabled` switch were
15001
+ * retired unimplemented).
15002
+ */
15003
+ /** Separator between the source and the slot id in a `slotRef`. It is the
15004
+ * D554 routing separator: the dispatcher matches `<source>:` prefixes. */
15005
+ var EXTENSION_SLOT_REF_SEPARATOR = ":";
15006
+ /** The contract method whose failure BECOMES a row, like `listSources`'s. */
15007
+ var EXTENSION_SLOT_LISTING_METHOD = "listSlots";
15008
+ var ExtensionSourceAvailabilitySchema = zod.z.discriminatedUnion("state", [zod.z.object({ state: zod.z.literal("ok") }), zod.z.object({
15009
+ state: zod.z.literal("unreachable"),
15010
+ reason: zod.z.string()
15011
+ })]);
15012
+ /** One provider of slots — the D554 source-listing row. */
15013
+ var ExtensionSourceSchema = zod.z.object({
15014
+ /** The routing prefix of every `slotRef` this provider serves. */
15015
+ source: zod.z.string(),
15016
+ label: zod.z.string(),
15017
+ /** Stamped by the dispatcher from the registry (D557). */
15018
+ addonId: zod.z.string().optional(),
15019
+ availability: ExtensionSourceAvailabilitySchema
15020
+ });
15021
+ /**
15022
+ * How one picked source stands. `missing` — no such device (deleted, or an id
15023
+ * that never existed); `foreign` — a device the slot's owner cannot read from
15024
+ * (a source owned by another addon); `unavailable` — it exists but is not a
15025
+ * valid source now (a container, which is never a pick). A source in any of
15026
+ * these states is SHOWN, never silently dropped or re-pointed.
15027
+ */
15028
+ var ExtensionSourceHealthSchema = zod.z.enum([
15029
+ "ok",
15030
+ "missing",
15031
+ "foreign",
15032
+ "unavailable"
15033
+ ]);
15034
+ var ExtensionSlotSourceSchema = zod.z.object({
15035
+ deviceId: zod.z.number().int(),
15036
+ /** The device's name, or null when it could not be resolved (`missing`). */
15037
+ name: zod.z.string().nullable(),
15038
+ health: ExtensionSourceHealthSchema,
15039
+ detail: zod.z.string().optional()
15040
+ });
15041
+ /**
15042
+ * A DIFFERENT authority that gates whether the slot's sources do anything —
15043
+ * reported read-only, named, never written through this contract (D62). The
15044
+ * virtual doorbell's sources ring only while the wrapper is bound to the
15045
+ * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15046
+ * `unknown` means the gate could not be read; it is not "inactive" (D315).
15047
+ */
15048
+ var ExtensionSlotActivationSchema = zod.z.object({
15049
+ state: zod.z.enum([
15050
+ "active",
15051
+ "inactive",
15052
+ "unknown"
15053
+ ]),
15054
+ authority: zod.z.string(),
15055
+ detail: zod.z.string().optional()
15056
+ });
15057
+ /** One slot of one device, as its owner reads it from its own store. */
15058
+ var ExtensionSlotStateSchema = zod.z.object({
15059
+ state: zod.z.literal("ok"),
15060
+ /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15061
+ slotRef: zod.z.string(),
15062
+ slot: ExtensionSlotIdSchema,
15063
+ /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15064
+ authority: zod.z.string(),
15065
+ activation: ExtensionSlotActivationSchema.nullable(),
15066
+ value: ExtensionSlotValueSchema,
15067
+ sources: zod.z.array(ExtensionSlotSourceSchema),
15068
+ /**
15069
+ * Devices the owner links to the host ON ITS OWN, by structure, and that
15070
+ * are therefore not in `value` (D655): a camera's device-tree children, and
15071
+ * the child a picked container stands for (D356 — a container is never a
15072
+ * pick, its children are). Read-only; the editor shows them and may offer
15073
+ * per-device options on them (the linked-devices tracked-event opt-in).
15074
+ * Absent when the owner links nothing beyond the picks, and from an owner
15075
+ * older than D655.
15076
+ */
15077
+ impliedSources: zod.z.array(ExtensionSlotSourceSchema).optional()
15078
+ });
15079
+ /**
15080
+ * A provider that could not answer `listSlots` at all. It could not name its
15081
+ * own slots, so the row names the ADDON and carries the refusal verbatim.
15082
+ * Written by the dispatcher, never by a provider.
15083
+ */
15084
+ var ExtensionSlotUnreachableSchema = zod.z.object({
15085
+ state: zod.z.literal("unreachable"),
15086
+ addonId: zod.z.string(),
15087
+ reason: zod.z.string()
15088
+ });
15089
+ var ExtensionSlotRowSchema = zod.z.discriminatedUnion("state", [ExtensionSlotStateSchema, ExtensionSlotUnreachableSchema]);
15090
+ /** The row the dispatcher writes for a provider whose `listSlots` threw. */
15091
+ function unreachableExtensionSlotRow(addonId, reason) {
15092
+ return {
15093
+ state: "unreachable",
15094
+ addonId,
15095
+ reason
15096
+ };
15097
+ }
15098
+ /** One device the slot's editor may offer as a source. */
15099
+ var ExtensionCandidateSchema = zod.z.object({
15100
+ deviceId: zod.z.number().int(),
15101
+ name: zod.z.string(),
15102
+ type: zod.z.string(),
15103
+ location: zod.z.string().nullable(),
15104
+ /** The container a child belongs to — "Spotlight 2" alone does not say which. */
15105
+ parentName: zod.z.string().nullable(),
15106
+ /** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
15107
+ suggested: zod.z.boolean(),
15108
+ /** Why it is suggested ("same location"), null when it is not. */
15109
+ reason: zod.z.string().nullable()
15110
+ });
15111
+ var ExtensionCandidatesSchema = zod.z.object({ candidates: zod.z.array(ExtensionCandidateSchema) });
15112
+ /**
15113
+ * What a write did. `none` — applied in place. `host` / `parent` — the owner
15114
+ * reloaded the host (or, for an accessory child, its parent) because the
15115
+ * write changed what the host REGISTERS. A slot never adds a capability to its
15116
+ * host — that is a composition (D663) — so today's owners answer `none`.
15117
+ */
15118
+ var ExtensionSetResultSchema = zod.z.object({
15119
+ applied: zod.z.literal(true),
15120
+ reload: zod.z.enum([
15121
+ "none",
15122
+ "host",
15123
+ "parent"
15124
+ ])
15125
+ });
15126
+ var ExtensionSlotRefInputSchema = zod.z.object({
15127
+ deviceId: zod.z.number().int(),
15128
+ slotRef: zod.z.string().min(1)
15129
+ });
15130
+ var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
15131
+ var deviceExtensionCapability = {
15132
+ name: "device-extension",
15133
+ scope: "device",
15134
+ mode: "collection",
15135
+ kind: "wrapper",
15136
+ defaultActive: true,
15137
+ deviceTypes: EXTENSION_HOST_DEVICE_TYPES,
15138
+ deviceConfig: { ui: {
15139
+ kind: "widget",
15140
+ widgetId: "host/extensions-panel",
15141
+ tab: "general",
15142
+ label: "Extensions",
15143
+ order: 72
15144
+ } },
15145
+ methods: {
15146
+ /** One row per slot owner — the D554 source listing `slotRef` routes by. */
15147
+ listSources: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int() }), zod.z.array(ExtensionSourceSchema)),
15148
+ /**
15149
+ * Every slot this device is offered, read by each owner from its own
15150
+ * store. A provider that throws is ONE `unreachable` row (D554.4).
15151
+ */
15152
+ listSlots: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int() }), zod.z.array(ExtensionSlotRowSchema)),
15153
+ /** The devices the slot's editor may offer, suggestions pre-marked (D356). */
15154
+ listCandidates: require_sleep.method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema),
15155
+ /**
15156
+ * Write one slot through its owner's EXISTING write path. The owner
15157
+ * validates (a container is never a linked device, a camera is never its
15158
+ * own source) and refuses by name before persisting.
15159
+ */
15160
+ setSlot: require_sleep.method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
15161
+ kind: "mutation",
15162
+ auth: "admin"
15163
+ })
15164
+ }
15165
+ };
15166
+ //#endregion
14718
15167
  //#region src/capabilities/device-state.cap.ts
14719
15168
  /**
14720
15169
  * Per-field ownership (D663). A composition may CLAIM fields of a native
@@ -18882,17 +19331,25 @@ var NcScheduleSchema = zod.z.object({
18882
19331
  */
18883
19332
  var NcSystemEventDeliveryModeSchema = zod.z.enum(["instant", "summary"]);
18884
19333
  /**
19334
+ * How a summary window is SENT (D698): `rule` (absent) = ONE notification with
19335
+ * every section; `section` = one notification per section with something to
19336
+ * say (an unavailable section included), each titled by its section.
19337
+ */
19338
+ var NcStateSummarySplitSchema = zod.z.enum(["rule", "section"]);
19339
+ /**
18885
19340
  * `summary`: the rule sends NOTHING per event. When a window of `schedule`
18886
19341
  * CLOSES, it sends one notification with the current state of its kinds
18887
19342
  * (low batteries, consumables to replace, devices offline, updates
18888
- * available, ...), after its own filters. Nothing to report sends nothing.
19343
+ * available, ...), after its own filters — or, with `split: 'section'`
19344
+ * (D698), one notification per section. Nothing to report sends nothing.
18889
19345
  * The schedule is the ordinary `NcSchedule` (weekly windows, IANA timezone,
18890
19346
  * midnight crossing); the send time is each window's END. Refused on the
18891
19347
  * `alarm` family, which stays instant (`systemEventDeliveryProblems`).
18892
19348
  */
18893
19349
  var NcSystemEventDeliverySchema = zod.z.discriminatedUnion("mode", [zod.z.object({ mode: zod.z.literal("instant") }), zod.z.object({
18894
19350
  mode: zod.z.literal("summary"),
18895
- schedule: NcScheduleSchema
19351
+ schedule: NcScheduleSchema,
19352
+ split: NcStateSummarySplitSchema.optional()
18896
19353
  })]);
18897
19354
  /** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
18898
19355
  var NcPlateMatcherSchema = zod.z.object({
@@ -19939,11 +20396,23 @@ var NcStateSummaryPreviewSectionSchema = zod.z.object({
19939
20396
  reason: zod.z.string().optional()
19940
20397
  });
19941
20398
  /**
20399
+ * One notification a previewed summary would send (D698): the whole summary on
20400
+ * a `rule` split (no `section`), one section's on a `section` split.
20401
+ */
20402
+ var NcStateSummaryPreviewRowSchema = zod.z.object({
20403
+ section: zod.z.string().optional(),
20404
+ /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
20405
+ title: zod.z.string(),
20406
+ text: zod.z.string(),
20407
+ count: zod.z.number().int().nonnegative()
20408
+ });
20409
+ /**
19942
20410
  * The summary a rule would send now. `empty` = nothing to report and every
19943
20411
  * section read: such a summary is NOT sent. `dropped` counts the open states
19944
20412
  * the rule's own filters (or a camera mute) left out, by reason.
19945
20413
  * `excludedGroups` names the kind groups selected that have no state to report
19946
- * (backups & exports).
20414
+ * (backups & exports). `split` and `rows` (D698) say how it would be sent —
20415
+ * optional, so an older hub's answer still parses.
19947
20416
  */
19948
20417
  var NcStateSummaryPreviewSchema = zod.z.object({
19949
20418
  empty: zod.z.boolean(),
@@ -19951,7 +20420,9 @@ var NcStateSummaryPreviewSchema = zod.z.object({
19951
20420
  text: zod.z.string(),
19952
20421
  sections: zod.z.array(NcStateSummaryPreviewSectionSchema),
19953
20422
  dropped: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative()),
19954
- excludedGroups: zod.z.array(zod.z.string())
20423
+ excludedGroups: zod.z.array(zod.z.string()),
20424
+ split: NcStateSummarySplitSchema.optional(),
20425
+ rows: zod.z.array(NcStateSummaryPreviewRowSchema).optional()
19955
20426
  });
19956
20427
  var NcTestResultSchema = zod.z.object({
19957
20428
  recordId: zod.z.string(),
@@ -31312,337 +31783,6 @@ var CLIP_PLAYBACK_OPTIONS = {
31312
31783
  }
31313
31784
  };
31314
31785
  //#endregion
31315
- //#region src/capabilities/doorbell.cap.ts
31316
- /**
31317
- * Doorbell button cap. Two kinds of providers coexist behind this cap
31318
- * name (same pattern as `snapshot`):
31319
- *
31320
- * - **Native** providers: registered per-device by device-driver
31321
- * addons via `ctx.registerNativeCap` — either on a
31322
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
31323
- * or directly on the camera (Reolink registers at camera level).
31324
- * Emits an `onPressed` event every time the firmware pushes a
31325
- * ring; status tracks the last press and a pressCount since start
31326
- * (diagnostic).
31327
- *
31328
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
31329
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
31330
- * device (contact / switch / event-emitter …) into a doorbell for
31331
- * a camera. `defaultActive: false` — the operator explicitly binds
31332
- * it per camera in the device-bindings UI, then picks the source
31333
- * device + trigger in the per-device settings.
31334
- *
31335
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
31336
- * — subscribers listening at the camera level receive ring events
31337
- * with `via[]` populated. No code on the parent needed.
31338
- */
31339
- var DoorbellStatusSchema = zod.z.object({
31340
- /** Ms epoch of the last press. null = never observed since this provider started. */
31341
- lastPressedAt: zod.z.number().nullable(),
31342
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
31343
- pressCountSinceStart: zod.z.number()
31344
- });
31345
- var DoorbellPressEventSchema = zod.z.object({
31346
- deviceId: zod.z.number(),
31347
- timestamp: zod.z.number()
31348
- });
31349
- /**
31350
- * The `doorbell-source` extension slot's editable value (D648): the camera's
31351
- * virtual-doorbell trigger devices, exactly what the wrapper's
31352
- * `doorbellSources` persists (as `{ deviceId }` records).
31353
- */
31354
- var DoorbellSourceSlotValueSchema = zod.z.object({ deviceIds: zod.z.array(zod.z.number().int().positive()) });
31355
- /**
31356
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
31357
- * doorbell, owned by the `virtual-doorbell` wrapper over its
31358
- * `doorbellSources` store (D648). A source rings when one of its
31359
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
31360
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
31361
- * reports it, it never writes it.
31362
- */
31363
- var DOORBELL_SOURCE_SLOT = {
31364
- id: "doorbell-source",
31365
- label: "Doorbell trigger devices",
31366
- description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
31367
- shape: "association",
31368
- hostDeviceTypes: [require_err_msg.DeviceType.Camera],
31369
- sourceCaps: require_composition.SOURCE_CAPS,
31370
- cardinality: "many",
31371
- value: DoorbellSourceSlotValueSchema
31372
- };
31373
- var doorbellCapability = {
31374
- name: "doorbell",
31375
- scope: "device",
31376
- deviceNative: true,
31377
- mode: "singleton",
31378
- kind: "wrapper",
31379
- defaultActive: false,
31380
- deviceTypes: [require_err_msg.DeviceType.Button, require_err_msg.DeviceType.Camera],
31381
- extensionSlots: [DOORBELL_SOURCE_SLOT],
31382
- methods: {},
31383
- events: {
31384
- /**
31385
- * Fires once per physical press. Reolink delivers via Baichuan
31386
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
31387
- * release/duration — it's a pulse.
31388
- */
31389
- onPressed: {
31390
- data: DoorbellPressEventSchema,
31391
- fromState: {
31392
- field: "lastPressedAt",
31393
- on: "advance"
31394
- }
31395
- } },
31396
- status: {
31397
- schema: DoorbellStatusSchema,
31398
- kind: "push"
31399
- },
31400
- /**
31401
- * Runtime-state slice — last press timestamp + lifetime press count.
31402
- * Mirrored by the kernel and readable via
31403
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
31404
- * without subscribing.
31405
- */
31406
- runtimeState: DoorbellStatusSchema,
31407
- /**
31408
- * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
31409
- *
31410
- * See `RuntimeStateDurability`. Enforced by
31411
- * `scripts/check-runtime-state-durability.ts`.
31412
- */
31413
- durability: "restored"
31414
- };
31415
- //#endregion
31416
- //#region src/generated/extension-slots.ts
31417
- /**
31418
- * AUTO-GENERATED by scripts/generate-extension-slots.ts — DO NOT EDIT.
31419
- *
31420
- * Every extension slot declared by a capability (`extensionSlots` in its
31421
- * `*.cap.ts`, D648), folded into one typed table. Imports ONLY the declaring
31422
- * caps' descriptors and value schemas — never the caps barrel — so
31423
- * `device-extension.cap.ts` can import this module without a cycle.
31424
- *
31425
- * Coverage: 2 slot(s).
31426
- */
31427
- /** Every declared slot id, in table order. */
31428
- var EXTENSION_SLOT_IDS = ["doorbell-source", "linked-devices"];
31429
- var ExtensionSlotIdSchema = zod.z.enum(EXTENSION_SLOT_IDS);
31430
- var EXTENSION_SLOTS = {
31431
- "doorbell-source": {
31432
- descriptor: DOORBELL_SOURCE_SLOT,
31433
- declaringCap: "doorbell",
31434
- hostDeviceTypes: [require_err_msg.DeviceType.Camera]
31435
- },
31436
- "linked-devices": {
31437
- descriptor: LINKED_DEVICES_SLOT,
31438
- declaringCap: "device-manager",
31439
- hostDeviceTypes: [require_err_msg.DeviceType.Camera]
31440
- }
31441
- };
31442
- /** A slot's editable value, discriminated on `slot`. */
31443
- var ExtensionSlotValueSchema = zod.z.discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: zod.z.literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: zod.z.literal("linked-devices") })]);
31444
- /** Every device type at least one slot is offered on — `device-extension`'s `deviceTypes`. */
31445
- var EXTENSION_HOST_DEVICE_TYPES = [require_err_msg.DeviceType.Camera];
31446
- //#endregion
31447
- //#region src/capabilities/device-extension.cap.ts
31448
- /**
31449
- * `device-extension` — ONE place to see and author what a device is extended
31450
- * with by OTHER devices (D648).
31451
- *
31452
- * **A contract, not a store.** Every slot (`linked-devices`, `doorbell-source`)
31453
- * is declared by the cap that owns the function (`extensionSlots` in its
31454
- * `*.cap.ts`, D4) and SERVED by the addon that already owns its store, over
31455
- * that store and its existing write path. This cap persists nothing and has no config method (guarded by
31456
- * `scripts/check-extension-slots.ts`): D62 applied to the whole feature, and
31457
- * D3 — no shadow registry.
31458
- *
31459
- * **Shape.** A device-scoped wrapper COLLECTION, the D554 shape `videoclips`
31460
- * uses: `resolveCapMount` gives it the `device-scoped` mount and
31461
- * `requireDeviceCollection` dispatches it. Its providers are the slot owners
31462
- * (device-manager, virtual-doorbell, …), and a device's sources are its
31463
- * bindings (step 0 of `getBindings`, derived, persisted nowhere).
31464
- *
31465
- * - `listSources` — one row per provider, the D554 source-listing convention
31466
- * that lets a scalar call be routed by the prefix of its `slotRef`.
31467
- * - `listSlots` — fan-out, concatenated. A provider that throws becomes ONE
31468
- * `unreachable` row naming it, never an absence (D554.4, D315): "no
31469
- * extensions" is claimed only from an answer.
31470
- * - `listCandidates` / `setSlot` — scalar, routed by `slotRef`
31471
- * (`<source>:<slotId>`). An unclaimed ref is refused by name (D554.5).
31472
- *
31473
- * The slot's value travels as the generated discriminated union
31474
- * (`ExtensionSlotValue`, keyed on `slot`), so a value under the wrong slot is
31475
- * a schema error before it reaches any owner.
31476
- *
31477
- * **Associations only.** A slot LISTS other devices on its host. A host that
31478
- * GAINS a capability from other devices is a composition (D663, amends D648:
31479
- * the reserved `graft` shape, its `projects` and its `enabled` switch were
31480
- * retired unimplemented).
31481
- */
31482
- /** Separator between the source and the slot id in a `slotRef`. It is the
31483
- * D554 routing separator: the dispatcher matches `<source>:` prefixes. */
31484
- var EXTENSION_SLOT_REF_SEPARATOR = ":";
31485
- /** The contract method whose failure BECOMES a row, like `listSources`'s. */
31486
- var EXTENSION_SLOT_LISTING_METHOD = "listSlots";
31487
- var ExtensionSourceAvailabilitySchema = zod.z.discriminatedUnion("state", [zod.z.object({ state: zod.z.literal("ok") }), zod.z.object({
31488
- state: zod.z.literal("unreachable"),
31489
- reason: zod.z.string()
31490
- })]);
31491
- /** One provider of slots — the D554 source-listing row. */
31492
- var ExtensionSourceSchema = zod.z.object({
31493
- /** The routing prefix of every `slotRef` this provider serves. */
31494
- source: zod.z.string(),
31495
- label: zod.z.string(),
31496
- /** Stamped by the dispatcher from the registry (D557). */
31497
- addonId: zod.z.string().optional(),
31498
- availability: ExtensionSourceAvailabilitySchema
31499
- });
31500
- /**
31501
- * How one picked source stands. `missing` — no such device (deleted, or an id
31502
- * that never existed); `foreign` — a device the slot's owner cannot read from
31503
- * (a source owned by another addon); `unavailable` — it exists but is not a
31504
- * valid source now (a container, which is never a pick). A source in any of
31505
- * these states is SHOWN, never silently dropped or re-pointed.
31506
- */
31507
- var ExtensionSourceHealthSchema = zod.z.enum([
31508
- "ok",
31509
- "missing",
31510
- "foreign",
31511
- "unavailable"
31512
- ]);
31513
- var ExtensionSlotSourceSchema = zod.z.object({
31514
- deviceId: zod.z.number().int(),
31515
- /** The device's name, or null when it could not be resolved (`missing`). */
31516
- name: zod.z.string().nullable(),
31517
- health: ExtensionSourceHealthSchema,
31518
- detail: zod.z.string().optional()
31519
- });
31520
- /**
31521
- * A DIFFERENT authority that gates whether the slot's sources do anything —
31522
- * reported read-only, named, never written through this contract (D62). The
31523
- * virtual doorbell's sources ring only while the wrapper is bound to the
31524
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
31525
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
31526
- */
31527
- var ExtensionSlotActivationSchema = zod.z.object({
31528
- state: zod.z.enum([
31529
- "active",
31530
- "inactive",
31531
- "unknown"
31532
- ]),
31533
- authority: zod.z.string(),
31534
- detail: zod.z.string().optional()
31535
- });
31536
- /** One slot of one device, as its owner reads it from its own store. */
31537
- var ExtensionSlotStateSchema = zod.z.object({
31538
- state: zod.z.literal("ok"),
31539
- /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
31540
- slotRef: zod.z.string(),
31541
- slot: ExtensionSlotIdSchema,
31542
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
31543
- authority: zod.z.string(),
31544
- activation: ExtensionSlotActivationSchema.nullable(),
31545
- value: ExtensionSlotValueSchema,
31546
- sources: zod.z.array(ExtensionSlotSourceSchema),
31547
- /**
31548
- * Devices the owner links to the host ON ITS OWN, by structure, and that
31549
- * are therefore not in `value` (D655): a camera's device-tree children, and
31550
- * the child a picked container stands for (D356 — a container is never a
31551
- * pick, its children are). Read-only; the editor shows them and may offer
31552
- * per-device options on them (the linked-devices tracked-event opt-in).
31553
- * Absent when the owner links nothing beyond the picks, and from an owner
31554
- * older than D655.
31555
- */
31556
- impliedSources: zod.z.array(ExtensionSlotSourceSchema).optional()
31557
- });
31558
- /**
31559
- * A provider that could not answer `listSlots` at all. It could not name its
31560
- * own slots, so the row names the ADDON and carries the refusal verbatim.
31561
- * Written by the dispatcher, never by a provider.
31562
- */
31563
- var ExtensionSlotUnreachableSchema = zod.z.object({
31564
- state: zod.z.literal("unreachable"),
31565
- addonId: zod.z.string(),
31566
- reason: zod.z.string()
31567
- });
31568
- var ExtensionSlotRowSchema = zod.z.discriminatedUnion("state", [ExtensionSlotStateSchema, ExtensionSlotUnreachableSchema]);
31569
- /** The row the dispatcher writes for a provider whose `listSlots` threw. */
31570
- function unreachableExtensionSlotRow(addonId, reason) {
31571
- return {
31572
- state: "unreachable",
31573
- addonId,
31574
- reason
31575
- };
31576
- }
31577
- /** One device the slot's editor may offer as a source. */
31578
- var ExtensionCandidateSchema = zod.z.object({
31579
- deviceId: zod.z.number().int(),
31580
- name: zod.z.string(),
31581
- type: zod.z.string(),
31582
- location: zod.z.string().nullable(),
31583
- /** The container a child belongs to — "Spotlight 2" alone does not say which. */
31584
- parentName: zod.z.string().nullable(),
31585
- /** Pre-marked by the owner's suggestion rule. NEVER saved on its own (D356). */
31586
- suggested: zod.z.boolean(),
31587
- /** Why it is suggested ("same location"), null when it is not. */
31588
- reason: zod.z.string().nullable()
31589
- });
31590
- var ExtensionCandidatesSchema = zod.z.object({ candidates: zod.z.array(ExtensionCandidateSchema) });
31591
- /**
31592
- * What a write did. `none` — applied in place. `host` / `parent` — the owner
31593
- * reloaded the host (or, for an accessory child, its parent) because the
31594
- * write changed what the host REGISTERS. A slot never adds a capability to its
31595
- * host — that is a composition (D663) — so today's owners answer `none`.
31596
- */
31597
- var ExtensionSetResultSchema = zod.z.object({
31598
- applied: zod.z.literal(true),
31599
- reload: zod.z.enum([
31600
- "none",
31601
- "host",
31602
- "parent"
31603
- ])
31604
- });
31605
- var ExtensionSlotRefInputSchema = zod.z.object({
31606
- deviceId: zod.z.number().int(),
31607
- slotRef: zod.z.string().min(1)
31608
- });
31609
- var ExtensionSetSlotInputSchema = ExtensionSlotRefInputSchema.extend({ value: ExtensionSlotValueSchema });
31610
- var deviceExtensionCapability = {
31611
- name: "device-extension",
31612
- scope: "device",
31613
- mode: "collection",
31614
- kind: "wrapper",
31615
- defaultActive: true,
31616
- deviceTypes: EXTENSION_HOST_DEVICE_TYPES,
31617
- deviceConfig: { ui: {
31618
- kind: "widget",
31619
- widgetId: "host/extensions-panel",
31620
- tab: "general",
31621
- label: "Extensions",
31622
- order: 72
31623
- } },
31624
- methods: {
31625
- /** One row per slot owner — the D554 source listing `slotRef` routes by. */
31626
- listSources: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int() }), zod.z.array(ExtensionSourceSchema)),
31627
- /**
31628
- * Every slot this device is offered, read by each owner from its own
31629
- * store. A provider that throws is ONE `unreachable` row (D554.4).
31630
- */
31631
- listSlots: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int() }), zod.z.array(ExtensionSlotRowSchema)),
31632
- /** The devices the slot's editor may offer, suggestions pre-marked (D356). */
31633
- listCandidates: require_sleep.method(ExtensionSlotRefInputSchema, ExtensionCandidatesSchema),
31634
- /**
31635
- * Write one slot through its owner's EXISTING write path. The owner
31636
- * validates (a container is never a linked device, a camera is never its
31637
- * own source) and refuses by name before persisting.
31638
- */
31639
- setSlot: require_sleep.method(ExtensionSetSlotInputSchema, ExtensionSetResultSchema, {
31640
- kind: "mutation",
31641
- auth: "admin"
31642
- })
31643
- }
31644
- };
31645
- //#endregion
31646
31786
  //#region src/capabilities/webrtc-session.cap.ts
31647
31787
  /**
31648
31788
  * Optional client-side hints sent at session creation to help the provider
@@ -51703,6 +51843,7 @@ var CAPABILITY_NAMES = {
51703
51843
  cover: "cover",
51704
51844
  customModelRegistry: "custom-model-registry",
51705
51845
  dataStoreProvider: "data-store-provider",
51846
+ databaseSnapshot: "database-snapshot",
51706
51847
  dayNight: "day-night",
51707
51848
  decoder: "decoder",
51708
51849
  detectionPipeline: "detection-pipeline",
@@ -51994,6 +52135,10 @@ var CAPABILITY_ROUTER_KEYS = [
51994
52135
  key: "dataStoreProvider",
51995
52136
  name: "data-store-provider"
51996
52137
  },
52138
+ {
52139
+ key: "databaseSnapshot",
52140
+ name: "database-snapshot"
52141
+ },
51997
52142
  {
51998
52143
  key: "dayNight",
51999
52144
  name: "day-night"
@@ -52527,6 +52672,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
52527
52672
  coverCapability,
52528
52673
  customModelRegistryCapability,
52529
52674
  dataStoreProviderCapability,
52675
+ databaseSnapshotCapability,
52530
52676
  dayNightCapability,
52531
52677
  decoderCapability,
52532
52678
  detectionPipelineCapability,
@@ -53791,6 +53937,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
53791
53937
  addonId: null,
53792
53938
  access: "view"
53793
53939
  },
53940
+ "databaseSnapshot.listDatabases": {
53941
+ capName: "database-snapshot",
53942
+ capScope: "system",
53943
+ addonId: null,
53944
+ access: "view"
53945
+ },
53946
+ "databaseSnapshot.writeSnapshot": {
53947
+ capName: "database-snapshot",
53948
+ capScope: "system",
53949
+ addonId: null,
53950
+ access: "create"
53951
+ },
53794
53952
  "dataStoreProvider.aggregate": {
53795
53953
  capName: "data-store-provider",
53796
53954
  capScope: "system",
@@ -59872,6 +60030,7 @@ var KNOWN_CAP_NAMES = [
59872
60030
  "cover",
59873
60031
  "custom-model-registry",
59874
60032
  "data-store-provider",
60033
+ "database-snapshot",
59875
60034
  "day-night",
59876
60035
  "decoder",
59877
60036
  "detection-pipeline",
@@ -60105,6 +60264,7 @@ var SYSTEM_CAP_NAMES = [
60105
60264
  "core-blocks",
60106
60265
  "custom-model-registry",
60107
60266
  "data-store-provider",
60267
+ "database-snapshot",
60108
60268
  "decoder",
60109
60269
  "device-adoption",
60110
60270
  "device-export",
@@ -65487,6 +65647,18 @@ var STATE_SUMMARY_VARS = [
65487
65647
  systemEventKinds: [...SUMMARISABLE],
65488
65648
  systemEventDeliveries: ["summary"]
65489
65649
  },
65650
+ {
65651
+ name: "summarySection",
65652
+ label: "Summary: this section",
65653
+ description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
65654
+ example: "Batterie scariche",
65655
+ group: "system",
65656
+ families: ["rule"],
65657
+ fields: [...RULE_TEXT],
65658
+ kinds: ["system"],
65659
+ systemEventKinds: [...SUMMARISABLE],
65660
+ systemEventDeliveries: ["summary"]
65661
+ },
65490
65662
  ...STATE_SUMMARY_SECTION_VARS.map((v) => ({
65491
65663
  name: v.name,
65492
65664
  label: v.label,
@@ -66329,6 +66501,15 @@ function systemEventSummaryScheduleOf(rule) {
66329
66501
  const delivery = rule.systemEventDelivery;
66330
66502
  return delivery?.mode === "summary" ? delivery.schedule : null;
66331
66503
  }
66504
+ /**
66505
+ * How a summary rule's window is sent (D698): `section` = one notification per
66506
+ * section; absent (every rule before D698) and any non-summary rule = `rule`.
66507
+ * The ONE reader — the scheduler, the rule test, the preview and both editors.
66508
+ */
66509
+ function systemEventSummarySplitOf(rule) {
66510
+ const delivery = rule.systemEventDelivery;
66511
+ return delivery?.mode === "summary" ? delivery.split ?? "rule" : "rule";
66512
+ }
66332
66513
  /** Absent and `instant` are the same answer: a notification per event. */
66333
66514
  function isSystemEventSummaryRule(rule) {
66334
66515
  return systemEventSummaryScheduleOf(rule) !== null;
@@ -69139,6 +69320,7 @@ exports.AppleFmAvailabilitySchema = AppleFmAvailabilitySchema;
69139
69320
  exports.AppleFmUnavailableReasonSchema = AppleFmUnavailableReasonSchema;
69140
69321
  exports.ArchiveEntrySchema = ArchiveEntrySchema;
69141
69322
  exports.ArchiveManifestSchema = ArchiveManifestSchema;
69323
+ exports.ArchiveSqliteSnapshotSchema = ArchiveSqliteSnapshotSchema;
69142
69324
  exports.ArchivedDebugNoteQueryInputSchema = ArchivedDebugNoteQueryInputSchema;
69143
69325
  exports.ArchivedDebugNoteSchema = ArchivedDebugNoteSchema;
69144
69326
  exports.AttachmentMediaTypeSchema = AttachmentMediaTypeSchema;
@@ -69419,6 +69601,9 @@ exports.CreateScopedTokenResultSchema = CreateScopedTokenResultSchema;
69419
69601
  exports.CreateUserInputSchema = CreateUserInputSchema;
69420
69602
  exports.CustomActionInputSchema = CustomActionInputSchema;
69421
69603
  exports.CustomModelDescriptorSchema = CustomModelDescriptorSchema;
69604
+ exports.DATABASE_SNAPSHOT_PARTIAL_SUFFIX = DATABASE_SNAPSHOT_PARTIAL_SUFFIX;
69605
+ exports.DATABASE_SNAPSHOT_SUFFIX = DATABASE_SNAPSHOT_SUFFIX;
69606
+ exports.DATABASE_SNAPSHOT_TIMEOUT_MS = DATABASE_SNAPSHOT_TIMEOUT_MS;
69422
69607
  exports.DATAPLANE_SECRET_HEADER = require_sleep.DATAPLANE_SECRET_HEADER;
69423
69608
  exports.DAYS_PER_WEEK = DAYS_PER_WEEK;
69424
69609
  exports.DAY_NAMES = DAY_NAMES;
@@ -69469,6 +69654,9 @@ exports.DISPLAY_ICON_VOCABULARY = DISPLAY_ICON_VOCABULARY;
69469
69654
  exports.DOORBELL_RISE_DEBOUNCE_MS = DOORBELL_RISE_DEBOUNCE_MS;
69470
69655
  exports.DOORBELL_SOURCE_SLOT = DOORBELL_SOURCE_SLOT;
69471
69656
  exports.DataStoreEngineInfoSchema = EngineInfoSchema;
69657
+ exports.DatabaseSnapshotResultSchema = DatabaseSnapshotResultSchema;
69658
+ exports.DatabaseSnapshotTableSchema = DatabaseSnapshotTableSchema;
69659
+ exports.DatabaseSnapshotTargetsSchema = DatabaseSnapshotTargetsSchema;
69472
69660
  exports.DayNightModeSchema = DayNightModeSchema;
69473
69661
  exports.DayNightOptionsSchema = DayNightOptionsSchema;
69474
69662
  exports.DayNightSettingsPatchSchema = DayNightSettingsPatchSchema;
@@ -69983,8 +70171,10 @@ exports.NcSnoozeInputSchema = NcSnoozeInputSchema;
69983
70171
  exports.NcSnoozeSchema = NcSnoozeSchema;
69984
70172
  exports.NcSnoozeScopeSchema = NcSnoozeScopeSchema;
69985
70173
  exports.NcSnoozeSuppressedSchema = NcSnoozeSuppressedSchema;
70174
+ exports.NcStateSummaryPreviewRowSchema = NcStateSummaryPreviewRowSchema;
69986
70175
  exports.NcStateSummaryPreviewSchema = NcStateSummaryPreviewSchema;
69987
70176
  exports.NcStateSummaryPreviewSectionSchema = NcStateSummaryPreviewSectionSchema;
70177
+ exports.NcStateSummarySplitSchema = NcStateSummarySplitSchema;
69988
70178
  exports.NcSystemEventConditionSchema = NcSystemEventConditionSchema;
69989
70179
  exports.NcSystemEventDeliveryModeSchema = NcSystemEventDeliveryModeSchema;
69990
70180
  exports.NcSystemEventDeliverySchema = NcSystemEventDeliverySchema;
@@ -70630,6 +70820,7 @@ exports.createSystemProxy = createSystemProxy;
70630
70820
  exports.customAction = require_sleep.customAction;
70631
70821
  exports.customModelRegistryCapability = customModelRegistryCapability;
70632
70822
  exports.dataStoreProviderCapability = dataStoreProviderCapability;
70823
+ exports.databaseSnapshotCapability = databaseSnapshotCapability;
70633
70824
  exports.dayNightCapability = dayNightCapability;
70634
70825
  exports.dayOfWeekToIndex = dayOfWeekToIndex;
70635
70826
  exports.declarationOwnerNodeId = declarationOwnerNodeId;
@@ -71058,6 +71249,7 @@ exports.systemEventFilterAppliesToAnyKind = systemEventFilterAppliesToAnyKind;
71058
71249
  exports.systemEventKindNamesOf = systemEventKindNamesOf;
71059
71250
  exports.systemEventKindsOfFamily = systemEventKindsOfFamily;
71060
71251
  exports.systemEventSummaryScheduleOf = systemEventSummaryScheduleOf;
71252
+ exports.systemEventSummarySplitOf = systemEventSummarySplitOf;
71061
71253
  exports.systemFamilyOfKind = systemFamilyOfKind;
71062
71254
  exports.systemRuleKindOf = systemRuleKindOf;
71063
71255
  exports.tamperCapability = tamperCapability;