@camstack/system 1.2.28 → 1.2.29

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 (58) hide show
  1. package/dist/addon-runner.js +3 -3
  2. package/dist/addon-runner.mjs +2 -2
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.d.ts +0 -7
  8. package/dist/builtins/alerts/alerts.addon.js +47 -25
  9. package/dist/builtins/alerts/alerts.addon.mjs +47 -25
  10. package/dist/builtins/alerts/prune-policy.d.ts +44 -0
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  22. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  23. package/dist/builtins/local-network/local-network.addon.js +1 -1
  24. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  25. package/dist/builtins/loki-logging/index.js +1 -1
  26. package/dist/builtins/loki-logging/index.mjs +1 -1
  27. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  28. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  29. package/dist/builtins/platform-probe/index.js +1 -1
  30. package/dist/builtins/platform-probe/index.mjs +1 -1
  31. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  32. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  33. package/dist/builtins/snapshot/index.js +1 -1
  34. package/dist/builtins/snapshot/index.mjs +1 -1
  35. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  36. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +7 -1
  38. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +8 -2
  39. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +22 -4
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +22 -4
  41. package/dist/builtins/storage-orchestrator/data-store-dispatch.d.ts +12 -0
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +18 -7
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +78 -11
  44. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +78 -11
  45. package/dist/builtins/system-config/system-config.addon.js +1 -1
  46. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  47. package/dist/builtins/winston-logging/index.js +1 -1
  48. package/dist/builtins/winston-logging/index.mjs +1 -1
  49. package/dist/{dist-BXmFvn3h.mjs → dist-B7hOpr5i.mjs} +411 -166
  50. package/dist/{dist-BxtIzexq.js → dist-CPmFYLqq.js} +416 -165
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.js +106 -2
  53. package/dist/index.mjs +102 -3
  54. package/dist/kernel/heap-watch.d.ts +36 -0
  55. package/dist/kernel/transport/uds-event-bus.d.ts +4 -1
  56. package/dist/{manifest-python-deps-KZ00cbfP.js → manifest-python-deps-BqE5j0-O.js} +25 -4
  57. package/dist/{manifest-python-deps-BNOApgK0.mjs → manifest-python-deps-Ck4-9K9m.mjs} +25 -4
  58. package/package.json +7 -3
@@ -3381,14 +3381,7 @@ var RecordingConfigSchema = zod.z.object({
3381
3381
  * windows only — existing sheets are immutable, and each window's index
3382
3382
  * carries its own tile dims so mixed-preset history renders correctly.
3383
3383
  */
3384
- scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
3385
- /**
3386
- * OPT-IN thumbnail-strip generation for this camera: every keyframe of the
3387
- * low recording saved as a JPEG (the fast-drag scrub depth), a derived
3388
- * cache that eviction reclaims with the footage. Absent/false = no strips
3389
- * are written and scrub reads exact keyframes at every velocity.
3390
- */
3391
- stripsEnabled: zod.z.boolean().optional()
3384
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
3392
3385
  }).strict();
3393
3386
  /**
3394
3387
  * Ops-log — the durable, append-only operations audit shared by the
@@ -3450,7 +3443,7 @@ var OpsLogQueryInputSchema = zod.z.object({
3450
3443
  /**
3451
3444
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
3452
3445
  *
3453
- * One shape shared by the recorder's `relocateFootage` (segments + strips) and
3446
+ * One shape shared by the recorder's `relocateFootage` (segments) and
3454
3447
  * pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
3455
3448
  * page renders both movers with one component. Jobs are in-RAM (a restart
3456
3449
  * forgets them — re-running is safe by construction: copy-if-absent, delete
@@ -3472,7 +3465,7 @@ var RelocateJobSchema = zod.z.object({
3472
3465
  toLocationId: zod.z.string(),
3473
3466
  /** Scoped device, or null = every device. */
3474
3467
  deviceId: zod.z.number().nullable(),
3475
- /** What the job moves (owner-addon specific: segments/strips or media). */
3468
+ /** What the job moves (owner-addon specific: segments or media). */
3476
3469
  entities: zod.z.array(zod.z.string()),
3477
3470
  filesMoved: zod.z.number().int(),
3478
3471
  bytesMoved: zod.z.number().int(),
@@ -3486,7 +3479,7 @@ var RelocateFootageInputSchema = zod.z.object({
3486
3479
  deviceId: zod.z.number().optional(),
3487
3480
  fromLocationId: zod.z.string(),
3488
3481
  toLocationId: zod.z.string(),
3489
- entities: zod.z.array(zod.z.enum(["segments", "strips"])).optional(),
3482
+ entities: zod.z.array(zod.z.enum(["segments"])).optional(),
3490
3483
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
3491
3484
  * never allowed to starve live writers. */
3492
3485
  throttleMbps: zod.z.number().min(1).max(1e3).optional()
@@ -14538,6 +14531,292 @@ var decoderCapability = {
14538
14531
  }
14539
14532
  };
14540
14533
  /**
14534
+ * Query filter for settings-store collections.
14535
+ */
14536
+ var QueryFilterSchema = zod.z.object({
14537
+ where: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
14538
+ whereIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
14539
+ whereBetween: zod.z.record(zod.z.string(), zod.z.tuple([zod.z.unknown(), zod.z.unknown()])).optional(),
14540
+ orderBy: zod.z.object({
14541
+ field: zod.z.string(),
14542
+ direction: zod.z.enum(["asc", "desc"])
14543
+ }).optional(),
14544
+ limit: zod.z.number().optional(),
14545
+ offset: zod.z.number().optional()
14546
+ });
14547
+ /** A single stored record: `{ id, data }`. */
14548
+ var SettingsRecordSchema = zod.z.object({
14549
+ id: zod.z.string(),
14550
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
14551
+ });
14552
+ /**
14553
+ * Column declaration for a structured (SQL-backed) collection.
14554
+ *
14555
+ * Logical types — the backend translates each to the matching SQLite
14556
+ * storage class and handles per-type marshaling:
14557
+ * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
14558
+ * - `JSON` — TEXT under the hood; serialised on write, parsed on read
14559
+ * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
14560
+ */
14561
+ var CollectionColumnSchema = zod.z.object({
14562
+ name: zod.z.string(),
14563
+ type: zod.z.enum([
14564
+ "TEXT",
14565
+ "INTEGER",
14566
+ "REAL",
14567
+ "JSON",
14568
+ "BOOLEAN"
14569
+ ]),
14570
+ primaryKey: zod.z.boolean().optional(),
14571
+ notNull: zod.z.boolean().optional(),
14572
+ unique: zod.z.boolean().optional()
14573
+ });
14574
+ var CollectionIndexSchema = zod.z.object({
14575
+ name: zod.z.string(),
14576
+ columns: zod.z.array(zod.z.string()).readonly(),
14577
+ unique: zod.z.boolean().optional()
14578
+ });
14579
+ /**
14580
+ * settings-store — singleton capability for addon-scoped persistence.
14581
+ *
14582
+ * Every method operates within a `collection`. An optional `namespace`
14583
+ * field provides access to additional data spaces beyond the default
14584
+ * addon settings — useful for business data (events, tracks, faces, etc.).
14585
+ *
14586
+ * **Scoping is the CALLER's, and it is opt-in.** The table is
14587
+ * `namespace ? `${namespace}:${collection}` : collection` — nothing
14588
+ * consults the identity of the caller. An earlier version of this comment
14589
+ * claimed the implementation prefixes every collection with the calling
14590
+ * addon's ID and that "addons never see each other's data"; that was never
14591
+ * true, and this same file contradicted it under `declareCollection`. What
14592
+ * exists is `addon-context-factory`, which passes `namespace: addonId` ON
14593
+ * THE ADDON'S BEHALF for the `addon-settings` / `addon-devices` paths only.
14594
+ * Business collections use bare names, and any caller may name any
14595
+ * namespace, or none. Making the door enforce it is tracked separately —
14596
+ * it renames tables, so it needs a migration.
14597
+ *
14598
+ * - `{ collection: 'addon-settings' }` → table `addon-settings`
14599
+ * - `{ namespace: 'my-addon', collection: 'addon-settings' }` →
14600
+ * table `my-addon:addon-settings`
14601
+ *
14602
+ * Served by the **storage-orchestrator** builtin, which dispatches to the
14603
+ * `data-store-provider` engine registered for the collection
14604
+ * (`sqlite-settings`, a SQLite WAL backend, today). One addon owns the
14605
+ * data door; engines sit behind it
14606
+ * ([D44](../../../../docs/decisions/adr-0044.md)).
14607
+ * Addons access it via `ctx.api.settingsStore.*`.
14608
+ */
14609
+ var settingsStoreCapability = {
14610
+ name: "settings-store",
14611
+ scope: "system",
14612
+ mode: "singleton",
14613
+ methods: {
14614
+ /** Get a single value by key from a collection. */
14615
+ get: method(zod.z.object({
14616
+ namespace: zod.z.string().optional(),
14617
+ collection: zod.z.string(),
14618
+ key: zod.z.string()
14619
+ }), zod.z.unknown()),
14620
+ /** Set a value by key in a collection (upsert). */
14621
+ set: method(zod.z.object({
14622
+ namespace: zod.z.string().optional(),
14623
+ collection: zod.z.string(),
14624
+ key: zod.z.string(),
14625
+ value: zod.z.unknown()
14626
+ }), zod.z.void(), { kind: "mutation" }),
14627
+ /** Get all entries matching an optional filter. */
14628
+ query: method(zod.z.object({
14629
+ namespace: zod.z.string().optional(),
14630
+ collection: zod.z.string(),
14631
+ filter: QueryFilterSchema.optional()
14632
+ }), zod.z.array(SettingsRecordSchema).readonly()),
14633
+ /** Insert a new record. */
14634
+ insert: method(zod.z.object({
14635
+ namespace: zod.z.string().optional(),
14636
+ collection: zod.z.string(),
14637
+ record: SettingsRecordSchema
14638
+ }), zod.z.void(), { kind: "mutation" }),
14639
+ /** Update an existing record by ID. */
14640
+ update: method(zod.z.object({
14641
+ namespace: zod.z.string().optional(),
14642
+ collection: zod.z.string(),
14643
+ id: zod.z.string(),
14644
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
14645
+ }), zod.z.void(), { kind: "mutation" }),
14646
+ /** Delete a record by key/ID. */
14647
+ delete: method(zod.z.object({
14648
+ namespace: zod.z.string().optional(),
14649
+ collection: zod.z.string(),
14650
+ key: zod.z.string()
14651
+ }), zod.z.void(), { kind: "mutation" }),
14652
+ /** Count entries in a collection, optionally filtered. */
14653
+ count: method(zod.z.object({
14654
+ namespace: zod.z.string().optional(),
14655
+ collection: zod.z.string(),
14656
+ filter: QueryFilterSchema.optional()
14657
+ }), zod.z.number()),
14658
+ /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
14659
+ histogram: method(zod.z.object({
14660
+ namespace: zod.z.string().optional(),
14661
+ collection: zod.z.string(),
14662
+ field: zod.z.string(),
14663
+ bucketSize: zod.z.number().int().positive(),
14664
+ origin: zod.z.number().int(),
14665
+ filter: QueryFilterSchema.optional()
14666
+ }), zod.z.array(zod.z.object({
14667
+ bucket: zod.z.number().int(),
14668
+ count: zod.z.number().int()
14669
+ })).readonly()),
14670
+ /** Check if a collection is empty. */
14671
+ isEmpty: method(zod.z.object({
14672
+ namespace: zod.z.string().optional(),
14673
+ collection: zod.z.string()
14674
+ }), zod.z.boolean()),
14675
+ /**
14676
+ * Declare a typed (SQL-backed) collection with explicit columns +
14677
+ * indexes. Idempotent: re-declaring an existing collection with the
14678
+ * same shape is a no-op; shape changes (new columns, new indexes)
14679
+ * are applied additively. Subsequent `insert` / `update` / `delete`
14680
+ * / `query` calls on this collection use typed columns instead of
14681
+ * JSON-blob storage — `record.data` fields are spread across
14682
+ * columns, `query.filter.where` matches real columns (no
14683
+ * `json_extract` overhead), `orderBy` uses column indexes.
14684
+ *
14685
+ * Addons call this in `onInitialize` before their first read/write.
14686
+ * Collection names should be namespaced by addon (e.g.
14687
+ * `pipeline-analytics:object-events`) to avoid cross-addon
14688
+ * clashes — no automatic prefix is added.
14689
+ */
14690
+ declareCollection: method(zod.z.object({
14691
+ namespace: zod.z.string().optional(),
14692
+ collection: zod.z.string(),
14693
+ columns: zod.z.array(CollectionColumnSchema).readonly(),
14694
+ indexes: zod.z.array(CollectionIndexSchema).readonly().optional()
14695
+ }), zod.z.void(), { kind: "mutation" })
14696
+ }
14697
+ };
14698
+ /**
14699
+ * What one engine says about itself. The orchestrator uses `kind` to pick
14700
+ * a registrant for a collection; `engineId` is what a log line names when
14701
+ * a call is routed or refused.
14702
+ */
14703
+ var EngineInfoSchema = zod.z.object({
14704
+ engineId: zod.z.string(),
14705
+ /**
14706
+ * `relational` — rows, columns, indexes, the surface `settings-store`
14707
+ * has always described. `vector` — an embedding store answering
14708
+ * similarity queries. A registrant declares exactly one; an engine that
14709
+ * does both registers twice, because "both" would make the routing
14710
+ * decision ambiguous at exactly the point it must not be.
14711
+ */
14712
+ kind: zod.z.enum(["relational", "vector"]),
14713
+ displayName: zod.z.string()
14714
+ });
14715
+ /**
14716
+ * data-store-provider — the engine contract behind the data door.
14717
+ *
14718
+ * The sibling of `storage-provider`, for rows instead of bytes. The
14719
+ * orchestrator (singleton `settings-store` cap, owned by the
14720
+ * storage-orchestrator builtin) dispatches every call to the registrant
14721
+ * that serves the collection.
14722
+ *
14723
+ * `internal: true` — consumed only by the orchestrator. Public consumers
14724
+ * go through `settings-store`; they never see this cap, and an engine
14725
+ * never sees a caller.
14726
+ *
14727
+ * Design notes:
14728
+ * - **Stateless dispatch.** Every method carries its own
14729
+ * `namespace` + `collection`, so an engine keeps no per-caller state
14730
+ * and the orchestrator forwards the payload verbatim. Scoping is a
14731
+ * property of the input, not of the connection — see the note on
14732
+ * `settings-store` about what that does and does not guarantee.
14733
+ * - **One registrant today** (`sqlite-settings`). The collection shape
14734
+ * exists so a second engine is a registration rather than a second
14735
+ * door ([D44](../../../../docs/decisions/adr-0044.md)).
14736
+ *
14737
+ * The method set is deliberately identical to `settings-store`'s: the
14738
+ * orchestrator is a router, not a translator. A capability the door
14739
+ * gains, an engine must be able to answer.
14740
+ */
14741
+ var dataStoreProviderCapability = {
14742
+ name: "data-store-provider",
14743
+ scope: "system",
14744
+ mode: "collection",
14745
+ internal: true,
14746
+ methods: {
14747
+ /** Self-description — how the orchestrator picks a registrant. */
14748
+ getEngineInfo: method(zod.z.void(), EngineInfoSchema),
14749
+ /** Get a single value by key from a collection. */
14750
+ get: method(zod.z.object({
14751
+ namespace: zod.z.string().optional(),
14752
+ collection: zod.z.string(),
14753
+ key: zod.z.string()
14754
+ }), zod.z.unknown()),
14755
+ /** Set a value by key in a collection (upsert). */
14756
+ set: method(zod.z.object({
14757
+ namespace: zod.z.string().optional(),
14758
+ collection: zod.z.string(),
14759
+ key: zod.z.string(),
14760
+ value: zod.z.unknown()
14761
+ }), zod.z.void(), { kind: "mutation" }),
14762
+ /** Get all entries matching an optional filter. */
14763
+ query: method(zod.z.object({
14764
+ namespace: zod.z.string().optional(),
14765
+ collection: zod.z.string(),
14766
+ filter: QueryFilterSchema.optional()
14767
+ }), zod.z.array(SettingsRecordSchema).readonly()),
14768
+ /** Insert a new record. */
14769
+ insert: method(zod.z.object({
14770
+ namespace: zod.z.string().optional(),
14771
+ collection: zod.z.string(),
14772
+ record: SettingsRecordSchema
14773
+ }), zod.z.void(), { kind: "mutation" }),
14774
+ /** Update an existing record by ID. */
14775
+ update: method(zod.z.object({
14776
+ namespace: zod.z.string().optional(),
14777
+ collection: zod.z.string(),
14778
+ id: zod.z.string(),
14779
+ data: zod.z.record(zod.z.string(), zod.z.unknown())
14780
+ }), zod.z.void(), { kind: "mutation" }),
14781
+ /** Delete a record by key/ID. */
14782
+ delete: method(zod.z.object({
14783
+ namespace: zod.z.string().optional(),
14784
+ collection: zod.z.string(),
14785
+ key: zod.z.string()
14786
+ }), zod.z.void(), { kind: "mutation" }),
14787
+ /** Count entries in a collection, optionally filtered. */
14788
+ count: method(zod.z.object({
14789
+ namespace: zod.z.string().optional(),
14790
+ collection: zod.z.string(),
14791
+ filter: QueryFilterSchema.optional()
14792
+ }), zod.z.number()),
14793
+ /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
14794
+ histogram: method(zod.z.object({
14795
+ namespace: zod.z.string().optional(),
14796
+ collection: zod.z.string(),
14797
+ field: zod.z.string(),
14798
+ bucketSize: zod.z.number().int().positive(),
14799
+ origin: zod.z.number().int(),
14800
+ filter: QueryFilterSchema.optional()
14801
+ }), zod.z.array(zod.z.object({
14802
+ bucket: zod.z.number().int(),
14803
+ count: zod.z.number().int()
14804
+ })).readonly()),
14805
+ /** Check if a collection is empty. */
14806
+ isEmpty: method(zod.z.object({
14807
+ namespace: zod.z.string().optional(),
14808
+ collection: zod.z.string()
14809
+ }), zod.z.boolean()),
14810
+ /** Declare a typed (SQL-backed) collection with columns + indexes. */
14811
+ declareCollection: method(zod.z.object({
14812
+ namespace: zod.z.string().optional(),
14813
+ collection: zod.z.string(),
14814
+ columns: zod.z.array(CollectionColumnSchema).readonly(),
14815
+ indexes: zod.z.array(CollectionIndexSchema).readonly().optional()
14816
+ }), zod.z.void(), { kind: "mutation" })
14817
+ }
14818
+ };
14819
+ /**
14541
14820
  * detection-pipeline — device-scoped facade over the system
14542
14821
  * `pipeline-executor`.
14543
14822
  *
@@ -18926,6 +19205,52 @@ var ServerUpdateStateSchema = zod.z.enum([
18926
19205
  "pending-restart",
18927
19206
  "awaiting-confirmation"
18928
19207
  ]);
19208
+ /**
19209
+ * Verdict of comparing the node's IMMUTABLE baked seed (the Docker image / the
19210
+ * desktop app bundle) against the release the deployment contract would
19211
+ * deliver today. `applyServerUpdate` swaps the data-root closure and NEVER
19212
+ * touches the image, so `runningVersion` can be perfectly current while the
19213
+ * container is weeks old, from a renamed repository nothing rebuilds — which
19214
+ * is exactly what happened on 2026-08-02 (hub on `camstack-server:intel-1.1.74`
19215
+ * while every existing surface said "up to date"). The seed version is the one
19216
+ * image fingerprint a container can see from inside (no docker socket).
19217
+ *
19218
+ * - `in-sync` — seed equals the current release; the node runs the
19219
+ * contract image.
19220
+ * - `behind-patch` — same release series, older patch: the image predates
19221
+ * the current release. Normal between deliberate image
19222
+ * refreshes, but the starter/entrypoint are still old.
19223
+ * - `behind-series` — the seed's major/minor predates the current release
19224
+ * series. The shape of a pinned tag or a dead image
19225
+ * repository; a `docker pull` may fix nothing.
19226
+ * - `ahead` — seed newer than the best-known release (stale registry
19227
+ * check).
19228
+ * - `unknown` — no seed (dev workspace) or nothing to compare against
19229
+ * yet.
19230
+ */
19231
+ var ImageContractStateSchema = zod.z.enum([
19232
+ "in-sync",
19233
+ "behind-patch",
19234
+ "behind-series",
19235
+ "ahead",
19236
+ "unknown"
19237
+ ]);
19238
+ var ImageContractSchema = zod.z.object({
19239
+ state: ImageContractStateSchema,
19240
+ /** The baked seed closure version — the image/app-bundle fingerprint. */
19241
+ seedVersion: zod.z.string().nullable(),
19242
+ /** Best-known version the deployment contract delivers today. */
19243
+ contractVersion: zod.z.string().nullable(),
19244
+ /**
19245
+ * Where `contractVersion` came from: a real registry check (`registry`), or
19246
+ * the node's own running version (`running` — a node can never run code
19247
+ * newer than the newest release, so `seed < running` proves image staleness
19248
+ * even before any registry check has run).
19249
+ */
19250
+ contractSource: zod.z.enum(["registry", "running"]).nullable(),
19251
+ /** One operator-grade sentence: this node runs image X; the contract says Y. */
19252
+ message: zod.z.string()
19253
+ });
18929
19254
  var ServerRollbackInfoSchema = zod.z.object({
18930
19255
  /** The version that failed (or was manually rolled back). */
18931
19256
  fromVersion: zod.z.string(),
@@ -18962,7 +19287,12 @@ var ServerPackageStatusSchema = zod.z.object({
18962
19287
  * versions are being IGNORED. Surfaced as a warning in the UI.
18963
19288
  */
18964
19289
  stateFileCorrupt: zod.z.boolean(),
18965
- lastCheckedAtMs: zod.z.number().nullable()
19290
+ lastCheckedAtMs: zod.z.number().nullable(),
19291
+ /**
19292
+ * Seed-vs-contract verdict (see {@link ImageContractSchema}). Optional for
19293
+ * version skew: an older provider's payload simply omits it.
19294
+ */
19295
+ imageContract: ImageContractSchema.optional()
18966
19296
  });
18967
19297
  var ServerUpdateCheckResultSchema = zod.z.object({
18968
19298
  packageName: zod.z.string(),
@@ -19017,158 +19347,6 @@ version: zod.z.string().optional() }), ServerUpdateActionResultSchema, {
19017
19347
  mount: { kind: "server-provided" }
19018
19348
  };
19019
19349
  /**
19020
- * Query filter for settings-store collections.
19021
- */
19022
- var QueryFilterSchema = zod.z.object({
19023
- where: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
19024
- whereIn: zod.z.record(zod.z.string(), zod.z.array(zod.z.unknown())).optional(),
19025
- whereBetween: zod.z.record(zod.z.string(), zod.z.tuple([zod.z.unknown(), zod.z.unknown()])).optional(),
19026
- orderBy: zod.z.object({
19027
- field: zod.z.string(),
19028
- direction: zod.z.enum(["asc", "desc"])
19029
- }).optional(),
19030
- limit: zod.z.number().optional(),
19031
- offset: zod.z.number().optional()
19032
- });
19033
- /** A single stored record: `{ id, data }`. */
19034
- var SettingsRecordSchema = zod.z.object({
19035
- id: zod.z.string(),
19036
- data: zod.z.record(zod.z.string(), zod.z.unknown())
19037
- });
19038
- /**
19039
- * Column declaration for a structured (SQL-backed) collection.
19040
- *
19041
- * Logical types — the backend translates each to the matching SQLite
19042
- * storage class and handles per-type marshaling:
19043
- * - `TEXT` / `INTEGER` / `REAL` — native SQLite types, pass-through
19044
- * - `JSON` — TEXT under the hood; serialised on write, parsed on read
19045
- * - `BOOLEAN` — INTEGER 0/1 under the hood; coerced both directions
19046
- */
19047
- var CollectionColumnSchema = zod.z.object({
19048
- name: zod.z.string(),
19049
- type: zod.z.enum([
19050
- "TEXT",
19051
- "INTEGER",
19052
- "REAL",
19053
- "JSON",
19054
- "BOOLEAN"
19055
- ]),
19056
- primaryKey: zod.z.boolean().optional(),
19057
- notNull: zod.z.boolean().optional(),
19058
- unique: zod.z.boolean().optional()
19059
- });
19060
- var CollectionIndexSchema = zod.z.object({
19061
- name: zod.z.string(),
19062
- columns: zod.z.array(zod.z.string()).readonly(),
19063
- unique: zod.z.boolean().optional()
19064
- });
19065
- /**
19066
- * settings-store — singleton capability for addon-scoped persistence.
19067
- *
19068
- * Every method operates within a `collection`. An optional `namespace`
19069
- * field provides access to additional data spaces beyond the default
19070
- * addon settings — useful for business data (events, tracks, faces, etc.).
19071
- *
19072
- * Scoping: the implementation prefixes every collection with the calling
19073
- * addon's ID automatically. Addons never see each other's data.
19074
- *
19075
- * - No namespace (default): `"addon-settings"` → `"<addonId>:addon-settings"`
19076
- * - With namespace: `{ namespace: 'events', collection: 'detections' }` →
19077
- * `"<addonId>:events:detections"`
19078
- *
19079
- * Implemented by `@camstack/system/builtins/sqlite-settings` (SQLite WAL backend).
19080
- * Addons access it via `ctx.api.settingsStore.*`.
19081
- */
19082
- var settingsStoreCapability = {
19083
- name: "settings-store",
19084
- scope: "system",
19085
- mode: "singleton",
19086
- methods: {
19087
- /** Get a single value by key from a collection. */
19088
- get: method(zod.z.object({
19089
- namespace: zod.z.string().optional(),
19090
- collection: zod.z.string(),
19091
- key: zod.z.string()
19092
- }), zod.z.unknown()),
19093
- /** Set a value by key in a collection (upsert). */
19094
- set: method(zod.z.object({
19095
- namespace: zod.z.string().optional(),
19096
- collection: zod.z.string(),
19097
- key: zod.z.string(),
19098
- value: zod.z.unknown()
19099
- }), zod.z.void(), { kind: "mutation" }),
19100
- /** Get all entries matching an optional filter. */
19101
- query: method(zod.z.object({
19102
- namespace: zod.z.string().optional(),
19103
- collection: zod.z.string(),
19104
- filter: QueryFilterSchema.optional()
19105
- }), zod.z.array(SettingsRecordSchema).readonly()),
19106
- /** Insert a new record. */
19107
- insert: method(zod.z.object({
19108
- namespace: zod.z.string().optional(),
19109
- collection: zod.z.string(),
19110
- record: SettingsRecordSchema
19111
- }), zod.z.void(), { kind: "mutation" }),
19112
- /** Update an existing record by ID. */
19113
- update: method(zod.z.object({
19114
- namespace: zod.z.string().optional(),
19115
- collection: zod.z.string(),
19116
- id: zod.z.string(),
19117
- data: zod.z.record(zod.z.string(), zod.z.unknown())
19118
- }), zod.z.void(), { kind: "mutation" }),
19119
- /** Delete a record by key/ID. */
19120
- delete: method(zod.z.object({
19121
- namespace: zod.z.string().optional(),
19122
- collection: zod.z.string(),
19123
- key: zod.z.string()
19124
- }), zod.z.void(), { kind: "mutation" }),
19125
- /** Count entries in a collection, optionally filtered. */
19126
- count: method(zod.z.object({
19127
- namespace: zod.z.string().optional(),
19128
- collection: zod.z.string(),
19129
- filter: QueryFilterSchema.optional()
19130
- }), zod.z.number()),
19131
- /** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
19132
- histogram: method(zod.z.object({
19133
- namespace: zod.z.string().optional(),
19134
- collection: zod.z.string(),
19135
- field: zod.z.string(),
19136
- bucketSize: zod.z.number().int().positive(),
19137
- origin: zod.z.number().int(),
19138
- filter: QueryFilterSchema.optional()
19139
- }), zod.z.array(zod.z.object({
19140
- bucket: zod.z.number().int(),
19141
- count: zod.z.number().int()
19142
- })).readonly()),
19143
- /** Check if a collection is empty. */
19144
- isEmpty: method(zod.z.object({
19145
- namespace: zod.z.string().optional(),
19146
- collection: zod.z.string()
19147
- }), zod.z.boolean()),
19148
- /**
19149
- * Declare a typed (SQL-backed) collection with explicit columns +
19150
- * indexes. Idempotent: re-declaring an existing collection with the
19151
- * same shape is a no-op; shape changes (new columns, new indexes)
19152
- * are applied additively. Subsequent `insert` / `update` / `delete`
19153
- * / `query` calls on this collection use typed columns instead of
19154
- * JSON-blob storage — `record.data` fields are spread across
19155
- * columns, `query.filter.where` matches real columns (no
19156
- * `json_extract` overhead), `orderBy` uses column indexes.
19157
- *
19158
- * Addons call this in `onInitialize` before their first read/write.
19159
- * Collection names should be namespaced by addon (e.g.
19160
- * `pipeline-analytics:object-events`) to avoid cross-addon
19161
- * clashes — no automatic prefix is added.
19162
- */
19163
- declareCollection: method(zod.z.object({
19164
- namespace: zod.z.string().optional(),
19165
- collection: zod.z.string(),
19166
- columns: zod.z.array(CollectionColumnSchema).readonly(),
19167
- indexes: zod.z.array(CollectionIndexSchema).readonly().optional()
19168
- }), zod.z.void(), { kind: "mutation" })
19169
- }
19170
- };
19171
- /**
19172
19350
  * `smtp-provider` — pluggable email delivery surface.
19173
19351
  *
19174
19352
  * Collection cap: a deployment may install multiple SMTP relays (e.g.
@@ -22878,7 +23056,7 @@ var recordingCapability = {
22878
23056
  auth: "admin"
22879
23057
  }),
22880
23058
  /**
22881
- * Move footage (segments and/or strips) from one recordings location to
23059
+ * Move footage (recorded segments) from one recordings location to
22882
23060
  * another — the drain workflow's mover (entity-routing spec Phase 4).
22883
23061
  * Throttled copy → size-verify → delete source → index refresh; resumable
22884
23062
  * by construction (copy-if-absent). Single-flight: one job at a time.
@@ -23761,6 +23939,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
23761
23939
  controlCapability,
23762
23940
  coverCapability,
23763
23941
  customModelRegistryCapability,
23942
+ dataStoreProviderCapability,
23764
23943
  dayNightCapability,
23765
23944
  decoderCapability,
23766
23945
  detectionPipelineCapability,
@@ -24766,6 +24945,72 @@ var METHOD_ACCESS_MAP = Object.freeze({
24766
24945
  addonId: null,
24767
24946
  access: "view"
24768
24947
  },
24948
+ "dataStoreProvider.count": {
24949
+ capName: "data-store-provider",
24950
+ capScope: "system",
24951
+ addonId: null,
24952
+ access: "view"
24953
+ },
24954
+ "dataStoreProvider.declareCollection": {
24955
+ capName: "data-store-provider",
24956
+ capScope: "system",
24957
+ addonId: null,
24958
+ access: "create"
24959
+ },
24960
+ "dataStoreProvider.delete": {
24961
+ capName: "data-store-provider",
24962
+ capScope: "system",
24963
+ addonId: null,
24964
+ access: "delete"
24965
+ },
24966
+ "dataStoreProvider.get": {
24967
+ capName: "data-store-provider",
24968
+ capScope: "system",
24969
+ addonId: null,
24970
+ access: "view"
24971
+ },
24972
+ "dataStoreProvider.getEngineInfo": {
24973
+ capName: "data-store-provider",
24974
+ capScope: "system",
24975
+ addonId: null,
24976
+ access: "view"
24977
+ },
24978
+ "dataStoreProvider.histogram": {
24979
+ capName: "data-store-provider",
24980
+ capScope: "system",
24981
+ addonId: null,
24982
+ access: "view"
24983
+ },
24984
+ "dataStoreProvider.insert": {
24985
+ capName: "data-store-provider",
24986
+ capScope: "system",
24987
+ addonId: null,
24988
+ access: "create"
24989
+ },
24990
+ "dataStoreProvider.isEmpty": {
24991
+ capName: "data-store-provider",
24992
+ capScope: "system",
24993
+ addonId: null,
24994
+ access: "view"
24995
+ },
24996
+ "dataStoreProvider.query": {
24997
+ capName: "data-store-provider",
24998
+ capScope: "system",
24999
+ addonId: null,
25000
+ access: "view"
25001
+ },
25002
+ "dataStoreProvider.set": {
25003
+ capName: "data-store-provider",
25004
+ capScope: "system",
25005
+ addonId: null,
25006
+ access: "create"
25007
+ },
25008
+ "dataStoreProvider.update": {
25009
+ capName: "data-store-provider",
25010
+ capScope: "system",
25011
+ addonId: null,
25012
+ access: "create"
25013
+ },
24769
25014
  "dayNight.getOptions": {
24770
25015
  capName: "day-night",
24771
25016
  capScope: "device",
@@ -29234,6 +29479,12 @@ Object.defineProperty(exports, "createEvent", {
29234
29479
  return createEvent;
29235
29480
  }
29236
29481
  });
29482
+ Object.defineProperty(exports, "dataStoreProviderCapability", {
29483
+ enumerable: true,
29484
+ get: function() {
29485
+ return dataStoreProviderCapability;
29486
+ }
29487
+ });
29237
29488
  Object.defineProperty(exports, "deviceManagerCapability", {
29238
29489
  enumerable: true,
29239
29490
  get: function() {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { startHeapWatch, buildHeapSample, HEAP_WATCH_INTERVAL_MS, HEAP_WATCH_WARN_RATIO, } from './kernel/heap-watch.js';
2
+ export type { HeapSample, HeapWatchSink } from './kernel/heap-watch.js';
1
3
  export { ensureBinary, downloadBinary, findInPath, getPlatformInfo, buildBinaryPath, ensureFfmpeg, getFfmpegDownloadUrl, ensurePython, installPythonPackages, installPythonRequirements, getPythonDownloadUrl, PYTHON_VERSION, } from '@camstack/types/node';
2
4
  export type { PlatformInfo } from '@camstack/types/node';
3
5
  export { ALL_CAPABILITY_DEFINITIONS, METHOD_ACCESS_MAP, expandCapMethods, isArrayOutputSchema, isCollectionArrayMethod, addonSettingsCapability, DEVICE_SETTINGS_CONTRIBUTION_METHODS, DEVICE_STATUS_METHOD, } from '@camstack/types';