@camstack/system 1.2.389 → 1.2.391

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 (503) hide show
  1. package/dist/addon/addon-api-factory.d.ts +30 -30
  2. package/dist/addon-routes/addon-route-registry.d.ts +31 -31
  3. package/dist/addon-runner.js +1 -1
  4. package/dist/addon-runner.mjs +1 -1
  5. package/dist/addon-utils.d.ts +22 -22
  6. package/dist/auth/admin-token-manager.d.ts +37 -67
  7. package/dist/auth/api-key-manager.d.ts +8 -8
  8. package/dist/auth/auth-audit-log.d.ts +29 -49
  9. package/dist/auth/auth-manager.d.ts +127 -126
  10. package/dist/auth/cidr.d.ts +8 -8
  11. package/dist/auth/external-identity-manager.d.ts +46 -34
  12. package/dist/auth/jwt-signing-key.d.ts +14 -14
  13. package/dist/auth/login-session-manager.d.ts +95 -135
  14. package/dist/auth/parse-record.d.ts +13 -13
  15. package/dist/auth/scope-matcher.d.ts +7 -7
  16. package/dist/auth/scoped-token-manager.d.ts +62 -62
  17. package/dist/auth/token-expiry.d.ts +49 -26
  18. package/dist/auth/totp-manager.d.ts +48 -48
  19. package/dist/auth/user-management-internal.d.ts +67 -52
  20. package/dist/auth/user-manager.d.ts +58 -58
  21. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +54 -54
  22. package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +22 -4
  23. package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -1
  24. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +54 -54
  25. package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -1
  26. package/dist/builtins/alerts/alerts.addon.d.ts +88 -87
  27. package/dist/builtins/alerts/device-label.d.ts +6 -6
  28. package/dist/builtins/alerts/index.d.ts +1 -1
  29. package/dist/builtins/alerts/prune-policy.d.ts +36 -36
  30. package/dist/builtins/autotrack/autotrack-cameras.d.ts +102 -79
  31. package/dist/builtins/autotrack/autotrack-config.d.ts +81 -81
  32. package/dist/builtins/autotrack/autotrack-decision.d.ts +69 -82
  33. package/dist/builtins/autotrack/autotrack-loop.d.ts +81 -61
  34. package/dist/builtins/autotrack/autotrack.addon.d.ts +103 -66
  35. package/dist/builtins/autotrack/frame-error.d.ts +38 -38
  36. package/dist/builtins/autotrack/frame-measurements.d.ts +79 -79
  37. package/dist/builtins/autotrack/index.d.ts +2 -2
  38. package/dist/builtins/autotrack/ptz-mirror.d.ts +46 -17
  39. package/dist/builtins/autotrack/target-selection.d.ts +33 -47
  40. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +270 -269
  41. package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +17 -17
  42. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +99 -82
  43. package/dist/builtins/backup-orchestrator/download-helpers.d.ts +9 -9
  44. package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +40 -29
  45. package/dist/builtins/backup-orchestrator/index.d.ts +2 -2
  46. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +88 -69
  47. package/dist/builtins/backup-orchestrator/restore-archive.d.ts +14 -14
  48. package/dist/builtins/backup-orchestrator/run-queue.d.ts +86 -86
  49. package/dist/builtins/backup-orchestrator/schedule-store.d.ts +53 -37
  50. package/dist/builtins/backup-orchestrator/staging-paths.d.ts +23 -23
  51. package/dist/builtins/backup-orchestrator/write-targets.d.ts +53 -53
  52. package/dist/builtins/calendars/calendar-color.d.ts +5 -1
  53. package/dist/builtins/calendars/calendar-prefs-store.d.ts +18 -12
  54. package/dist/builtins/calendars/calendars.addon.d.ts +16 -11
  55. package/dist/builtins/calendars/index.d.ts +1 -1
  56. package/dist/builtins/camera-grid/acquire-retry.d.ts +26 -26
  57. package/dist/builtins/camera-grid/addon.d.ts +200 -174
  58. package/dist/builtins/camera-grid/flv-join.d.ts +32 -58
  59. package/dist/builtins/camera-grid/grid-activity-mirror.d.ts +37 -37
  60. package/dist/builtins/camera-grid/grid-activity.d.ts +83 -42
  61. package/dist/builtins/camera-grid/grid-camera-declarations.d.ts +46 -46
  62. package/dist/builtins/camera-grid/grid-camera-device.d.ts +60 -34
  63. package/dist/builtins/camera-grid/grid-canvas-derivation.d.ts +50 -15
  64. package/dist/builtins/camera-grid/grid-canvas-seed.d.ts +96 -46
  65. package/dist/builtins/camera-grid/grid-canvas.d.ts +74 -74
  66. package/dist/builtins/camera-grid/grid-child.d.ts +29 -16
  67. package/dist/builtins/camera-grid/grid-compositor-child.d.ts +2 -2
  68. package/dist/builtins/camera-grid/grid-compositor-invocation.d.ts +39 -11
  69. package/dist/builtins/camera-grid/grid-compositor.d.ts +50 -50
  70. package/dist/builtins/camera-grid/grid-detection-mapping.d.ts +52 -22
  71. package/dist/builtins/camera-grid/grid-device-settings.d.ts +31 -7
  72. package/dist/builtins/camera-grid/grid-filter-graph.d.ts +41 -41
  73. package/dist/builtins/camera-grid/grid-frame-sample.d.ts +45 -19
  74. package/dist/builtins/camera-grid/grid-instances.d.ts +20 -50
  75. package/dist/builtins/camera-grid/grid-last-frame-store.d.ts +51 -51
  76. package/dist/builtins/camera-grid/grid-layout-native-provider.d.ts +30 -4
  77. package/dist/builtins/camera-grid/grid-plan.d.ts +30 -20
  78. package/dist/builtins/camera-grid/grid-profiles.d.ts +85 -45
  79. package/dist/builtins/camera-grid/grid-row-normalization.d.ts +6 -6
  80. package/dist/builtins/camera-grid/grid-sentry-sources.d.ts +57 -57
  81. package/dist/builtins/camera-grid/grid-snapshot.d.ts +41 -41
  82. package/dist/builtins/camera-grid/grid-stream-descriptor.d.ts +49 -21
  83. package/dist/builtins/camera-grid/grid-stream-invocation.d.ts +37 -22
  84. package/dist/builtins/camera-grid/grid-stream-relay.d.ts +26 -26
  85. package/dist/builtins/camera-grid/grid-stream-session.d.ts +123 -93
  86. package/dist/builtins/camera-grid/grid-tile-feed.d.ts +47 -47
  87. package/dist/builtins/camera-grid/grid-tile-plan.d.ts +55 -20
  88. package/dist/builtins/camera-grid/grid-wire-format.d.ts +22 -6
  89. package/dist/builtins/camera-grid/index.d.ts +44 -44
  90. package/dist/builtins/camera-grid/silence-analysis.d.ts +31 -14
  91. package/dist/builtins/composer/claim-gate.d.ts +54 -27
  92. package/dist/builtins/composer/composed-device-set.d.ts +40 -26
  93. package/dist/builtins/composer/composed-device.d.ts +39 -17
  94. package/dist/builtins/composer/composer-apply-waits.d.ts +20 -13
  95. package/dist/builtins/composer/composer-grafts.d.ts +57 -38
  96. package/dist/builtins/composer/composer-live-set.d.ts +15 -15
  97. package/dist/builtins/composer/composer-plan.d.ts +76 -60
  98. package/dist/builtins/composer/composer-runtime-factory.d.ts +21 -14
  99. package/dist/builtins/composer/composer-seeds.d.ts +20 -14
  100. package/dist/builtins/composer/composer-verdict.d.ts +28 -14
  101. package/dist/builtins/composer/composer.addon.d.ts +23 -9
  102. package/dist/builtins/composer/composer.d.ts +145 -100
  103. package/dist/builtins/composer/composition-declarations.d.ts +50 -39
  104. package/dist/builtins/composer/composition-evaluation.d.ts +38 -22
  105. package/dist/builtins/composer/composition-runtime.d.ts +178 -125
  106. package/dist/builtins/composer/composition-target.d.ts +38 -34
  107. package/dist/builtins/composer/confirmed-seed.d.ts +35 -23
  108. package/dist/builtins/composer/deadline-timer.d.ts +13 -13
  109. package/dist/builtins/composer/existing-target.d.ts +90 -73
  110. package/dist/builtins/composer/field-record.d.ts +26 -19
  111. package/dist/builtins/composer/graft-host.d.ts +56 -32
  112. package/dist/builtins/composer/held-claims.d.ts +26 -9
  113. package/dist/builtins/composer/index.d.ts +1 -1
  114. package/dist/builtins/composer/own-field-reads.d.ts +26 -15
  115. package/dist/builtins/composer/owned-fields-target.d.ts +75 -44
  116. package/dist/builtins/composer/slice-assembler.d.ts +19 -3
  117. package/dist/builtins/composer/source-readings.d.ts +67 -61
  118. package/dist/builtins/composer/source-tracker.d.ts +133 -69
  119. package/dist/builtins/console-logging/console-destination.d.ts +15 -8
  120. package/dist/builtins/console-logging/console-logging.addon.d.ts +20 -19
  121. package/dist/builtins/console-logging/index.d.ts +3 -3
  122. package/dist/builtins/core-blocks/block-package.d.ts +37 -37
  123. package/dist/builtins/core-blocks/block-settings-store.d.ts +34 -21
  124. package/dist/builtins/core-blocks/block-supervisor.d.ts +138 -117
  125. package/dist/builtins/core-blocks/block-type-defs.d.ts +21 -21
  126. package/dist/builtins/core-blocks/blocks-integration.d.ts +76 -49
  127. package/dist/builtins/core-blocks/compile-block.d.ts +37 -37
  128. package/dist/builtins/core-blocks/composition-api.d.ts +38 -24
  129. package/dist/builtins/core-blocks/composition-peers.d.ts +26 -4
  130. package/dist/builtins/core-blocks/composition-sources.d.ts +25 -10
  131. package/dist/builtins/core-blocks/core-block-store.d.ts +109 -109
  132. package/dist/builtins/core-blocks/core-blocks.addon.d.ts +72 -72
  133. package/dist/builtins/core-blocks/extract-settings-schema.d.ts +4 -4
  134. package/dist/builtins/core-blocks/index.d.ts +8 -8
  135. package/dist/builtins/device-manager/adoption-job-engine.d.ts +141 -98
  136. package/dist/builtins/device-manager/claimed-status-overlay.d.ts +42 -9
  137. package/dist/builtins/device-manager/contribution-cache.d.ts +56 -56
  138. package/dist/builtins/device-manager/day-night-config-schema.d.ts +26 -12
  139. package/dist/builtins/device-manager/device-aggregation-merge.d.ts +17 -17
  140. package/dist/builtins/device-manager/device-aggregation.d.ts +277 -254
  141. package/dist/builtins/device-manager/device-bindings-store.d.ts +232 -220
  142. package/dist/builtins/device-manager/device-config-contribution.d.ts +29 -29
  143. package/dist/builtins/device-manager/device-config-secrets.d.ts +32 -13
  144. package/dist/builtins/device-manager/device-event-propagator.d.ts +22 -22
  145. package/dist/builtins/device-manager/device-extension-linked-slot.d.ts +17 -17
  146. package/dist/builtins/device-manager/device-form-secrets.d.ts +14 -14
  147. package/dist/builtins/device-manager/device-linked-devices.d.ts +159 -98
  148. package/dist/builtins/device-manager/device-manager.addon.d.ts +223 -197
  149. package/dist/builtins/device-manager/device-meta-actions.d.ts +306 -305
  150. package/dist/builtins/device-manager/device-meta-store.d.ts +100 -90
  151. package/dist/builtins/device-manager/device-meta-types.d.ts +250 -241
  152. package/dist/builtins/device-manager/device-online-fallback.d.ts +30 -30
  153. package/dist/builtins/device-manager/device-projection.d.ts +53 -67
  154. package/dist/builtins/device-manager/device-provider-context.d.ts +109 -94
  155. package/dist/builtins/device-manager/device-queries.d.ts +63 -63
  156. package/dist/builtins/device-manager/device-row-store.d.ts +417 -365
  157. package/dist/builtins/device-manager/device-source-activation.d.ts +91 -49
  158. package/dist/builtins/device-manager/device-state-claim-views.d.ts +76 -61
  159. package/dist/builtins/device-manager/device-state-claims.d.ts +53 -30
  160. package/dist/builtins/device-manager/device-state-mirror.d.ts +256 -264
  161. package/dist/builtins/device-manager/device-sync-resolvers.d.ts +25 -25
  162. package/dist/builtins/device-manager/field-claims-index.d.ts +85 -58
  163. package/dist/builtins/device-manager/field-ownership.d.ts +54 -36
  164. package/dist/builtins/device-manager/fleet-read-census.d.ts +99 -61
  165. package/dist/builtins/device-manager/image-settings-config-schema.d.ts +18 -8
  166. package/dist/builtins/device-manager/index.d.ts +2 -2
  167. package/dist/builtins/device-manager/linked-devices-manual-backfill.d.ts +20 -9
  168. package/dist/builtins/device-manager/location-alignment.d.ts +46 -46
  169. package/dist/builtins/device-manager/migrate-device.d.ts +178 -101
  170. package/dist/builtins/device-manager/migrate-guard.d.ts +66 -34
  171. package/dist/builtins/device-manager/migrate-hardware-state.d.ts +59 -59
  172. package/dist/builtins/device-manager/migrate-reload.d.ts +42 -4
  173. package/dist/builtins/device-manager/migration-refused.d.ts +20 -20
  174. package/dist/builtins/device-manager/mirror-row-writer.d.ts +205 -179
  175. package/dist/builtins/device-manager/recording-onboard-config-schema.d.ts +56 -32
  176. package/dist/builtins/device-manager/removal-fence.d.ts +48 -48
  177. package/dist/builtins/device-manager/runtime-state-persist-gate.d.ts +54 -26
  178. package/dist/builtins/device-manager/secret-config-paths.d.ts +17 -17
  179. package/dist/builtins/device-manager/stale-wrapper-activations.d.ts +52 -25
  180. package/dist/builtins/device-manager/write-lock.d.ts +13 -13
  181. package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +41 -41
  182. package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +13 -12
  183. package/dist/builtins/hub-forwarder/index.d.ts +3 -3
  184. package/dist/builtins/keychain/index.d.ts +1 -1
  185. package/dist/builtins/keychain/key-sources.d.ts +19 -19
  186. package/dist/builtins/keychain/keychain-crypto.d.ts +4 -4
  187. package/dist/builtins/keychain/keychain-reset-trigger.d.ts +13 -13
  188. package/dist/builtins/keychain/keychain-service.d.ts +128 -128
  189. package/dist/builtins/keychain/keychain-store.d.ts +96 -87
  190. package/dist/builtins/keychain/keychain-usage.d.ts +13 -2
  191. package/dist/builtins/keychain/keychain.addon.d.ts +31 -6
  192. package/dist/builtins/keychain/platform-key-source.d.ts +15 -15
  193. package/dist/builtins/keychain/system-held-secrets.d.ts +17 -4
  194. package/dist/builtins/liveness-monitor/index.d.ts +2 -2
  195. package/dist/builtins/liveness-monitor/liveness-checks.d.ts +73 -52
  196. package/dist/builtins/liveness-monitor/liveness-monitor.addon.d.ts +57 -36
  197. package/dist/builtins/local-auth/admin-account-boot.d.ts +14 -14
  198. package/dist/builtins/local-auth/auth-config-reader.d.ts +34 -17
  199. package/dist/builtins/local-auth/auth-schema.d.ts +92 -69
  200. package/dist/builtins/local-auth/index.d.ts +1 -1
  201. package/dist/builtins/local-auth/jwt-signing-key-keeper.d.ts +22 -22
  202. package/dist/builtins/local-auth/local-auth.addon.d.ts +41 -40
  203. package/dist/builtins/local-auth/oauth-grants.d.ts +57 -57
  204. package/dist/builtins/local-auth/oauth-session-manager.d.ts +62 -62
  205. package/dist/builtins/local-network/address-book.d.ts +61 -36
  206. package/dist/builtins/local-network/index.d.ts +2 -2
  207. package/dist/builtins/local-network/ipv6-lan.d.ts +12 -17
  208. package/dist/builtins/local-network/local-hostname.d.ts +10 -10
  209. package/dist/builtins/local-network/local-network.addon.d.ts +259 -258
  210. package/dist/builtins/loki-logging/index.d.ts +4 -4
  211. package/dist/builtins/loki-logging/loki-destination.d.ts +113 -87
  212. package/dist/builtins/loki-logging/loki-logging.addon.d.ts +61 -42
  213. package/dist/builtins/loki-logging/loki-payload.d.ts +82 -39
  214. package/dist/builtins/loki-logging/retire-enabled-flag.d.ts +37 -12
  215. package/dist/builtins/native-metrics/cgroup-memory.d.ts +206 -159
  216. package/dist/builtins/native-metrics/cgroup-pids.d.ts +138 -91
  217. package/dist/builtins/native-metrics/container-memory-series.d.ts +212 -178
  218. package/dist/builtins/native-metrics/gpu-probe.d.ts +9 -9
  219. package/dist/builtins/native-metrics/index.d.ts +2 -2
  220. package/dist/builtins/native-metrics/load-series-config.d.ts +29 -57
  221. package/dist/builtins/native-metrics/load-series-reader.d.ts +52 -26
  222. package/dist/builtins/native-metrics/load-series-store.d.ts +237 -176
  223. package/dist/builtins/native-metrics/native-metrics-provider.d.ts +43 -43
  224. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +230 -230
  225. package/dist/builtins/native-metrics/node-load-ring.d.ts +196 -196
  226. package/dist/builtins/native-metrics/proc-process-table.d.ts +12 -12
  227. package/dist/builtins/native-metrics/process-classification.d.ts +95 -36
  228. package/dist/builtins/native-metrics/thread-cpu-sampler.d.ts +95 -95
  229. package/dist/builtins/platform-probe/coral-accelerators.d.ts +17 -17
  230. package/dist/builtins/platform-probe/index.d.ts +38 -30
  231. package/dist/builtins/platform-probe/inference-config-resolver.d.ts +27 -27
  232. package/dist/builtins/platform-probe/intel-accelerators.d.ts +8 -8
  233. package/dist/builtins/platform-probe/intel-npu.d.ts +30 -30
  234. package/dist/builtins/platform-probe/platform-scorer.d.ts +35 -35
  235. package/dist/builtins/platform-probe/runtime-packages.d.ts +3 -3
  236. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +87 -87
  237. package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -1
  238. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +66 -35
  239. package/dist/builtins/shared/device-state-changed.d.ts +9 -9
  240. package/dist/builtins/shared/settle-sources.d.ts +16 -16
  241. package/dist/builtins/snapshot/index.d.ts +2 -2
  242. package/dist/builtins/snapshot/snapshot-cache.d.ts +92 -92
  243. package/dist/builtins/snapshot/snapshot-coalescing.d.ts +108 -108
  244. package/dist/builtins/snapshot/snapshot-courtesy.d.ts +48 -48
  245. package/dist/builtins/snapshot/snapshot-durable-store.d.ts +32 -32
  246. package/dist/builtins/snapshot/snapshot-fatigue.d.ts +34 -34
  247. package/dist/builtins/snapshot/snapshot-grab-pick.d.ts +14 -14
  248. package/dist/builtins/snapshot/snapshot-link-url.d.ts +49 -49
  249. package/dist/builtins/snapshot/snapshot-media-handler.d.ts +97 -97
  250. package/dist/builtins/snapshot/snapshot-resize.d.ts +64 -103
  251. package/dist/builtins/snapshot/snapshot.addon.d.ts +569 -568
  252. package/dist/builtins/sqlite-storage/analyze-stats.d.ts +73 -29
  253. package/dist/builtins/sqlite-storage/config-store.d.ts +6 -6
  254. package/dist/builtins/sqlite-storage/device-store.d.ts +16 -16
  255. package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +23 -23
  256. package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +79 -79
  257. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +27 -26
  258. package/dist/builtins/sqlite-storage/filter-compiler.d.ts +107 -107
  259. package/dist/builtins/sqlite-storage/index.d.ts +12 -12
  260. package/dist/builtins/sqlite-storage/integration-registry.d.ts +37 -37
  261. package/dist/builtins/sqlite-storage/path-guard.d.ts +5 -5
  262. package/dist/builtins/sqlite-storage/prefix-range.d.ts +44 -44
  263. package/dist/builtins/sqlite-storage/query-bounds.d.ts +100 -106
  264. package/dist/builtins/sqlite-storage/query-profiler.d.ts +217 -217
  265. package/dist/builtins/sqlite-storage/retired-collections.d.ts +124 -55
  266. package/dist/builtins/sqlite-storage/retired-settings-keys.d.ts +239 -189
  267. package/dist/builtins/sqlite-storage/shm-lock-canary.d.ts +41 -41
  268. package/dist/builtins/sqlite-storage/sqlite-pragmas.d.ts +162 -162
  269. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +458 -458
  270. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +59 -58
  271. package/dist/builtins/sqlite-storage/sqlite-snapshot-protocol.d.ts +37 -32
  272. package/dist/builtins/sqlite-storage/sqlite-snapshot-worker.d.ts +19 -19
  273. package/dist/builtins/sqlite-storage/sqlite-snapshotter.d.ts +76 -76
  274. package/dist/builtins/sqlite-storage/statement-shape.d.ts +54 -54
  275. package/dist/builtins/sqlite-storage/table-sizes.d.ts +71 -71
  276. package/dist/builtins/sqlite-storage/vector-index-shared.d.ts +63 -54
  277. package/dist/builtins/sqlite-storage/vector-index-vec.d.ts +133 -96
  278. package/dist/builtins/sqlite-storage/wal-checkpoint-policy.d.ts +161 -161
  279. package/dist/builtins/sqlite-storage/wal-checkpointer.d.ts +60 -60
  280. package/dist/builtins/sqlite-storage/wal-maintenance.d.ts +94 -94
  281. package/dist/builtins/storage-orchestrator/access-guards.d.ts +37 -26
  282. package/dist/builtins/storage-orchestrator/data-store-dispatch.d.ts +33 -18
  283. package/dist/builtins/storage-orchestrator/drain-ratchet.d.ts +85 -85
  284. package/dist/builtins/storage-orchestrator/drain-state-store.d.ts +20 -10
  285. package/dist/builtins/storage-orchestrator/hub-settings-forward.d.ts +113 -53
  286. package/dist/builtins/storage-orchestrator/index.d.ts +7 -7
  287. package/dist/builtins/storage-orchestrator/location-occupancy-slice.d.ts +64 -40
  288. package/dist/builtins/storage-orchestrator/location-occupancy.d.ts +14 -14
  289. package/dist/builtins/storage-orchestrator/location-protection.d.ts +13 -13
  290. package/dist/builtins/storage-orchestrator/location-repoint-move.d.ts +44 -44
  291. package/dist/builtins/storage-orchestrator/location-root-collision.d.ts +61 -25
  292. package/dist/builtins/storage-orchestrator/location-secrets.d.ts +99 -58
  293. package/dist/builtins/storage-orchestrator/location-store.d.ts +56 -47
  294. package/dist/builtins/storage-orchestrator/location-volume-capacity.d.ts +37 -37
  295. package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +20 -6
  296. package/dist/builtins/storage-orchestrator/storage-cleanup-coordinator.d.ts +51 -51
  297. package/dist/builtins/storage-orchestrator/storage-migration-coordinator.d.ts +224 -224
  298. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +292 -292
  299. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +431 -450
  300. package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +104 -104
  301. package/dist/builtins/system-backup/backup-encryption.d.ts +60 -23
  302. package/dist/builtins/system-backup/system-backup.service.d.ts +240 -240
  303. package/dist/builtins/system-config/cluster-secret-keeper.d.ts +54 -34
  304. package/dist/builtins/system-config/index.d.ts +2 -2
  305. package/dist/builtins/system-config/mesh-actions.d.ts +2 -30
  306. package/dist/builtins/system-config/system-config.addon.d.ts +57 -93
  307. package/dist/builtins/system-config/system-config.addon.js +46 -33
  308. package/dist/builtins/system-config/system-config.addon.mjs +46 -33
  309. package/dist/builtins/winston-logging/index.d.ts +3 -3
  310. package/dist/builtins/winston-logging/winston-destination.d.ts +15 -15
  311. package/dist/builtins/winston-logging/winston-logging.addon.d.ts +14 -13
  312. package/dist/{child-cap-dispatch-nURMuVTX.js → child-cap-dispatch-Bnr8brru.js} +18 -0
  313. package/dist/{child-cap-dispatch-B1gyE35b.mjs → child-cap-dispatch-mHO_6r0G.mjs} +1 -1
  314. package/dist/download/hosted-model-revisions.d.ts +8 -8
  315. package/dist/download/model-download-service.d.ts +32 -32
  316. package/dist/download/model-downloader.d.ts +88 -88
  317. package/dist/events/event-bus.d.ts +6 -6
  318. package/dist/events/system-event-bus.d.ts +11 -11
  319. package/dist/feature/feature-manager.d.ts +6 -6
  320. package/dist/http/asset-compression.d.ts +35 -73
  321. package/dist/http/authenticated-file-server.d.ts +32 -32
  322. package/dist/http/data-plane-registry.d.ts +49 -39
  323. package/dist/http/file-data-plane.d.ts +14 -14
  324. package/dist/http/lan-http-bind.d.ts +24 -13
  325. package/dist/http/reverse-proxy.d.ts +36 -24
  326. package/dist/index.d.ts +137 -137
  327. package/dist/index.js +4 -3
  328. package/dist/index.mjs +2 -4
  329. package/dist/kernel/addon-class-resolver.d.ts +1 -1
  330. package/dist/kernel/addon-engine-manager.d.ts +20 -20
  331. package/dist/kernel/addon-health-monitor.d.ts +151 -151
  332. package/dist/kernel/addon-installer.d.ts +609 -609
  333. package/dist/kernel/addon-loader.d.ts +133 -133
  334. package/dist/kernel/addon-manifest.d.ts +118 -118
  335. package/dist/kernel/addon-residue.d.ts +28 -32
  336. package/dist/kernel/array-buffer-census.d.ts +84 -88
  337. package/dist/kernel/bootstrap-config.d.ts +3 -3
  338. package/dist/kernel/cap-router-builder.d.ts +145 -101
  339. package/dist/kernel/capability-handle.d.ts +41 -41
  340. package/dist/kernel/capability-registry.d.ts +588 -576
  341. package/dist/kernel/config-manager.d.ts +199 -199
  342. package/dist/kernel/config-schema.d.ts +132 -128
  343. package/dist/kernel/custom-action-registry.d.ts +25 -25
  344. package/dist/kernel/deps/addon-deps-manager.d.ts +17 -17
  345. package/dist/kernel/deps/closure-dedupe.d.ts +76 -76
  346. package/dist/kernel/deps/ensure-addon-natives.d.ts +34 -34
  347. package/dist/kernel/deps/ensure-native-prebuilds.d.ts +25 -25
  348. package/dist/kernel/deps/manifest-native-deps.d.ts +38 -38
  349. package/dist/kernel/deps/manifest-python-deps.d.ts +18 -18
  350. package/dist/kernel/deps/manifest-system-deps.d.ts +13 -13
  351. package/dist/kernel/deps/npm-command.d.ts +45 -45
  352. package/dist/kernel/deps/system-package-allowlist.d.ts +9 -9
  353. package/dist/kernel/deps/system-package-broker.d.ts +20 -20
  354. package/dist/kernel/deps/system-package-client.d.ts +3 -3
  355. package/dist/kernel/device-registry.d.ts +27 -27
  356. package/dist/kernel/event-loop-stall-monitor.d.ts +33 -33
  357. package/dist/kernel/event-plane-report.d.ts +174 -174
  358. package/dist/kernel/fs-utils.d.ts +70 -70
  359. package/dist/kernel/gc-census.d.ts +119 -119
  360. package/dist/kernel/heap-spaces.d.ts +87 -87
  361. package/dist/kernel/heap-watch.d.ts +706 -706
  362. package/dist/kernel/host-externals.d.ts +8 -8
  363. package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +27 -27
  364. package/dist/kernel/index.d.ts +115 -113
  365. package/dist/kernel/inference/inference-resolver.d.ts +13 -13
  366. package/dist/kernel/infra-capabilities.d.ts +7 -7
  367. package/dist/kernel/isolated-builtin-phase.d.ts +42 -42
  368. package/dist/kernel/lifecycle/job-journal.d.ts +17 -17
  369. package/dist/kernel/lifecycle/lifecycle-job-engine.d.ts +99 -99
  370. package/dist/kernel/lifecycle/staging-area.d.ts +22 -22
  371. package/dist/kernel/moleculer/addon-context-factory.d.ts +90 -89
  372. package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +12 -12
  373. package/dist/kernel/moleculer/addon-deploy-source.d.ts +11 -11
  374. package/dist/kernel/moleculer/addon-peer-bytes-facility.d.ts +18 -18
  375. package/dist/kernel/moleculer/addon-service-factory.d.ts +41 -41
  376. package/dist/kernel/moleculer/agent-mesh-authenticator.d.ts +60 -33
  377. package/dist/kernel/moleculer/agent-ui-unlock.d.ts +30 -30
  378. package/dist/kernel/moleculer/broker-factory.d.ts +61 -61
  379. package/dist/kernel/moleculer/cap-usage-registry.d.ts +108 -153
  380. package/dist/kernel/moleculer/capabilities-access.d.ts +19 -19
  381. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +43 -43
  382. package/dist/kernel/moleculer/child-cap-descriptors.d.ts +26 -26
  383. package/dist/kernel/moleculer/child-cap-dispatch.d.ts +52 -52
  384. package/dist/kernel/moleculer/children-batch-loader.d.ts +86 -34
  385. package/dist/kernel/moleculer/cluster-secret.d.ts +19 -19
  386. package/dist/kernel/moleculer/core-cap-service.d.ts +53 -53
  387. package/dist/kernel/moleculer/crash-supervisor.d.ts +39 -39
  388. package/dist/kernel/moleculer/device-cap-proxy.d.ts +51 -51
  389. package/dist/kernel/moleculer/device-event-ring.d.ts +117 -75
  390. package/dist/kernel/moleculer/event-bus-core.d.ts +171 -159
  391. package/dist/kernel/moleculer/event-bus.d.ts +73 -73
  392. package/dist/kernel/moleculer/hub-log-forwarder.d.ts +30 -30
  393. package/dist/kernel/moleculer/hub-service.d.ts +42 -42
  394. package/dist/kernel/moleculer/init-watchdog.d.ts +49 -49
  395. package/dist/kernel/moleculer/mesh-access-middleware.d.ts +36 -21
  396. package/dist/kernel/moleculer/mesh-auth-mode.d.ts +33 -39
  397. package/dist/kernel/moleculer/mesh-authenticator.d.ts +58 -58
  398. package/dist/kernel/moleculer/mesh-auto-enforce.d.ts +38 -18
  399. package/dist/kernel/moleculer/mesh-join-client.d.ts +67 -45
  400. package/dist/kernel/moleculer/mesh-join-proof.d.ts +8 -8
  401. package/dist/kernel/moleculer/mesh-mtls/constants.d.ts +1 -1
  402. package/dist/kernel/moleculer/mesh-mtls/index.d.ts +10 -10
  403. package/dist/kernel/moleculer/mesh-mtls/mesh-ca-keeper.d.ts +43 -38
  404. package/dist/kernel/moleculer/mesh-mtls/mesh-ca.d.ts +29 -20
  405. package/dist/kernel/moleculer/mesh-mtls/mesh-clear-port.d.ts +32 -32
  406. package/dist/kernel/moleculer/mesh-mtls/mesh-crl.d.ts +11 -11
  407. package/dist/kernel/moleculer/mesh-mtls/mesh-enroll.d.ts +19 -16
  408. package/dist/kernel/moleculer/mesh-mtls/mesh-join-token.d.ts +40 -40
  409. package/dist/kernel/moleculer/mesh-mtls/mesh-tls-enabler.d.ts +5 -1
  410. package/dist/kernel/moleculer/mesh-mtls/tls-tcp-transporter.d.ts +131 -130
  411. package/dist/kernel/moleculer/mesh-queue-report.d.ts +39 -39
  412. package/dist/kernel/moleculer/node-registry.d.ts +120 -120
  413. package/dist/kernel/moleculer/process-context.d.ts +2 -2
  414. package/dist/kernel/moleculer/process-service.d.ts +168 -168
  415. package/dist/kernel/moleculer/provider-registry.d.ts +9 -9
  416. package/dist/kernel/moleculer/readiness-context.d.ts +58 -58
  417. package/dist/kernel/moleculer/readiness-service.d.ts +31 -16
  418. package/dist/kernel/moleculer/register-framework-resolver.d.ts +6 -6
  419. package/dist/kernel/moleculer/register-node-client.d.ts +34 -27
  420. package/dist/kernel/moleculer/remote-logger.d.ts +29 -29
  421. package/dist/kernel/moleculer/resilient-cap-call.d.ts +21 -21
  422. package/dist/kernel/moleculer/runner-native-allocator.d.ts +95 -95
  423. package/dist/kernel/moleculer/runner-process-group.d.ts +57 -57
  424. package/dist/kernel/moleculer/runtime-state-load.d.ts +21 -11
  425. package/dist/kernel/moleculer/settings-read-guard.d.ts +39 -39
  426. package/dist/kernel/moleculer/stream-probe-service.d.ts +25 -6
  427. package/dist/kernel/moleculer/trpc-links.d.ts +203 -203
  428. package/dist/kernel/moleculer/typed-array-serde.d.ts +9 -20
  429. package/dist/kernel/moleculer/worker-device-restore.d.ts +8 -8
  430. package/dist/kernel/outbound-queue-watch.d.ts +74 -74
  431. package/dist/kernel/process-cpu-census.d.ts +55 -55
  432. package/dist/kernel/provider-kind-drift.d.ts +17 -8
  433. package/dist/kernel/restart-coordinator.d.ts +71 -71
  434. package/dist/kernel/settings-door-view.d.ts +36 -25
  435. package/dist/kernel/settings-read-error.d.ts +29 -31
  436. package/dist/kernel/settings-view-types.d.ts +100 -95
  437. package/dist/kernel/socket-plane-report.d.ts +214 -153
  438. package/dist/kernel/status-overlay.d.ts +31 -11
  439. package/dist/kernel/storage-location-registry.d.ts +50 -50
  440. package/dist/kernel/store-settings-view.d.ts +13 -13
  441. package/dist/kernel/system-settings-mirror.d.ts +40 -28
  442. package/dist/kernel/system-settings-policy.d.ts +15 -34
  443. package/dist/kernel/transport/cap-action-census.d.ts +183 -183
  444. package/dist/kernel/transport/cap-action-name.d.ts +84 -84
  445. package/dist/kernel/transport/cap-child-index.d.ts +41 -41
  446. package/dist/kernel/transport/cap-route-resolver.d.ts +237 -212
  447. package/dist/kernel/transport/cap-route.d.ts +139 -139
  448. package/dist/kernel/transport/cap-routing-hints.d.ts +37 -37
  449. package/dist/kernel/transport/child-cap-protocol.d.ts +245 -245
  450. package/dist/kernel/transport/claimed-get-status.d.ts +30 -6
  451. package/dist/kernel/transport/create-local-transport.d.ts +5 -5
  452. package/dist/kernel/transport/frame-codec.d.ts +109 -109
  453. package/dist/kernel/transport/hub-cap-forward.d.ts +81 -59
  454. package/dist/kernel/transport/index.d.ts +36 -36
  455. package/dist/kernel/transport/local-child-client.d.ts +184 -184
  456. package/dist/kernel/transport/local-child-registry.d.ts +592 -592
  457. package/dist/kernel/transport/local-endpoint-path.d.ts +4 -4
  458. package/dist/kernel/transport/local-transport.d.ts +92 -92
  459. package/dist/kernel/transport/parent-unowned-call.d.ts +266 -237
  460. package/dist/kernel/transport/peer-answered-error.d.ts +14 -14
  461. package/dist/kernel/transport/socket-channel.d.ts +110 -110
  462. package/dist/kernel/transport/socket-traffic.d.ts +96 -96
  463. package/dist/kernel/transport/uds-event-bridge.d.ts +77 -50
  464. package/dist/kernel/transport/uds-event-bus.d.ts +75 -26
  465. package/dist/kernel/transport/uds-local-transport.d.ts +14 -14
  466. package/dist/kernel/transport/uds-log-ingest.d.ts +38 -23
  467. package/dist/kernel/transport/uds-logger.d.ts +33 -33
  468. package/dist/kernel/utils/ring-buffer.d.ts +12 -12
  469. package/dist/kernel/workspace-detect.d.ts +7 -7
  470. package/dist/lifecycle/lifecycle-state-machine.d.ts +24 -24
  471. package/dist/logging/formatter.d.ts +52 -25
  472. package/dist/logging/log-manager.d.ts +133 -133
  473. package/dist/logging/log-redactor.d.ts +22 -1
  474. package/dist/logging/log-ring-buffer.d.ts +57 -57
  475. package/dist/logging/logging-gate.d.ts +69 -25
  476. package/dist/logging/logging-gate.singleton.d.ts +12 -1
  477. package/dist/logging/partitioned-log-buffer.d.ts +161 -161
  478. package/dist/logging/scoped-logger.d.ts +14 -14
  479. package/dist/network/network-quality.d.ts +8 -8
  480. package/dist/notification/notification-service.d.ts +37 -37
  481. package/dist/notification/toast-service.d.ts +18 -18
  482. package/dist/pipeline/engine-manager-resolver.d.ts +12 -12
  483. package/dist/pipeline/pipeline-runner.d.ts +6 -6
  484. package/dist/pipeline/pipeline-validator.d.ts +8 -8
  485. package/dist/process/proc-stat.d.ts +51 -51
  486. package/dist/process/resource-monitor.d.ts +19 -19
  487. package/dist/python/python-env-manager.d.ts +10 -10
  488. package/dist/repl/interfaces.d.ts +21 -21
  489. package/dist/repl/repl-engine.d.ts +6 -6
  490. package/dist/storage/fs-storage-backend.d.ts +35 -35
  491. package/dist/storage/storage-location-manager.d.ts +21 -21
  492. package/dist/storage/storage-manager.d.ts +68 -68
  493. package/dist/tls/boot-tls.d.ts +24 -24
  494. package/dist/tls/cert-evaluation.d.ts +25 -25
  495. package/dist/tls/cert-identity.d.ts +39 -39
  496. package/dist/tls/cert-issue.d.ts +37 -17
  497. package/dist/tls/cert-manager.d.ts +86 -84
  498. package/dist/tls/https-listener.d.ts +16 -16
  499. package/dist/tls/index.d.ts +8 -8
  500. package/dist/tls/tls-actions.d.ts +18 -18
  501. package/dist/tls/tls-status.d.ts +15 -15
  502. package/dist/tls/uploaded-cert.d.ts +9 -9
  503. package/package.json +9 -3
@@ -1,631 +1,631 @@
1
- import { InstalledPackage, IScopedLogger } from '@camstack/types';
2
- import { AddonManifest } from './addon-manifest.js';
3
1
  /**
4
- * Addon install source mode:
5
- * - 'npm' — download from npm registry (production + dev default).
6
- * - 'local' — copy dist/ from local workspace `packages/` (used by
7
- * `installFromWorkspace` + the Electron-packaged bundled
8
- * addons path).
9
- * - 'symlink' — point `data/addons/<pkg>` directly at the workspace
10
- * source dir. Dev-only: workspace edits → next addon
11
- * load picks them up after a `npm run build` of the
12
- * package, without re-copying. Costs ~80ms per addon at
13
- * cold boot instead of the ~200ms-per-package copy.
14
- * Windows fallback: drops back to `'local'` if symlink
15
- * creation fails (needs admin / developer-mode on Win10).
16
- *
17
- * The previous symlink mode (auto-on when workspace was detected) was
18
- * removed in `eb96df3c` once addons moved to self-contained bundles —
19
- * the legacy `symlinkAddonsToNodeModules` / `symlinkPeerDepsIntoAddonsDir`
20
- * helpers it relied on are GONE. This is the narrower successor: no
21
- * symlinks into the hub's `node_modules`, no peer-dep planting — just
22
- * `addonsDir/<pkg>` → `packages/<pkg>`.
23
- */
24
- export type InstallSource = 'npm' | 'local' | 'symlink';
2
+ * Addon install source mode:
3
+ * - 'npm' — download from npm registry (production + dev default).
4
+ * - 'local' — copy dist/ from local workspace `packages/` (used by
5
+ * `installFromWorkspace` + the Electron-packaged bundled
6
+ * addons path).
7
+ * - 'symlink' — point `data/addons/<pkg>` directly at the workspace
8
+ * source dir. Dev-only: workspace edits → next addon
9
+ * load picks them up after a `npm run build` of the
10
+ * package, without re-copying. Costs ~80ms per addon at
11
+ * cold boot instead of the ~200ms-per-package copy.
12
+ * Windows fallback: drops back to `'local'` if symlink
13
+ * creation fails (needs admin / developer-mode on Win10).
14
+ *
15
+ * The previous symlink mode (auto-on when workspace was detected) was
16
+ * removed in `eb96df3c` once addons moved to self-contained bundles —
17
+ * the legacy `symlinkAddonsToNodeModules` / `symlinkPeerDepsIntoAddonsDir`
18
+ * helpers it relied on are GONE. This is the narrower successor: no
19
+ * symlinks into the hub's `node_modules`, no peer-dep planting — just
20
+ * `addonsDir/<pkg>` → `packages/<pkg>`.
21
+ */
22
+ export type InstallSource = "npm" | "local" | "symlink";
25
23
  /** The one bootstrap package the server closure carries itself. */
26
24
  export declare const CLOSURE_PROVIDED_PACKAGE = "@camstack/system";
27
25
  /**
28
- * Should the bootstrap SKIP seeding `packageName` into /data/addons?
29
- *
30
- * True only for the package the closure provides, and only when it actually
31
- * resolves. Both halves are load-bearing:
32
- *
33
- * - seeding a copy the closure already provides creates one that WINS over
34
- * the closure and is never refreshed (bootstrap is seed-only, and
35
- * `camstack deploy` of a framework package is rejected on an image hub), so
36
- * the node runs first-boot builtins forever while reporting the new
37
- * version;
38
- * - skipping it when it does NOT resolve is how a fresh deployment was once
39
- * made unbootable ("No addon provides required infrastructure capability
40
- * storage-provider"). That is why the guard is resolvability rather than a
41
- * blanket removal from the bootstrap list.
42
- */
26
+ * Should the bootstrap SKIP seeding `packageName` into /data/addons?
27
+ *
28
+ * True only for the package the closure provides, and only when it actually
29
+ * resolves. Both halves are load-bearing:
30
+ *
31
+ * - seeding a copy the closure already provides creates one that WINS over
32
+ * the closure and is never refreshed (bootstrap is seed-only, and
33
+ * `camstack deploy` of a framework package is rejected on an image hub), so
34
+ * the node runs first-boot builtins forever while reporting the new
35
+ * version;
36
+ * - skipping it when it does NOT resolve is how a fresh deployment was once
37
+ * made unbootable ("No addon provides required infrastructure capability
38
+ * storage-provider"). That is why the guard is resolvability rather than a
39
+ * blanket removal from the bootstrap list.
40
+ */
43
41
  export declare function shouldSkipClosureProvidedSeed(packageName: string, isResolvable: boolean): boolean;
44
42
  export interface AddonInstallerConfig {
45
- /** Directory where addons are stored (e.g., {dataDir}/addons) */
46
- readonly addonsDir: string;
47
- /** npm registry URL */
48
- readonly registry?: string;
49
- /** Workspace packages directory (e.g., /path/to/camstack-server/packages) */
50
- readonly workspacePackagesDir?: string;
51
- /** Install source mode. Default: auto-detect */
52
- readonly installSource?: InstallSource;
53
- /**
54
- * Override for "does the running closure already provide this package?".
55
- * Production leaves it unset (real `require.resolve`); a spec sets it to
56
- * reach the branch that still seeds `@camstack/system`, which is otherwise
57
- * unreachable in a process where that package always resolves.
58
- */
59
- readonly isPackageResolvable?: (packageName: string) => boolean;
60
- /**
61
- * The server closure's node_modules to dedupe addon trees against.
62
- * Production leaves it unset (derived from `CAMSTACK_FRAMEWORK_DIR`);
63
- * specs point it at a fabricated closure dir.
64
- */
65
- readonly closureNodeModulesDir?: string;
43
+ /** Directory where addons are stored (e.g., {dataDir}/addons) */
44
+ readonly addonsDir: string;
45
+ /** npm registry URL */
46
+ readonly registry?: string;
47
+ /** Workspace packages directory (e.g., /path/to/camstack-server/packages) */
48
+ readonly workspacePackagesDir?: string;
49
+ /** Install source mode. Default: auto-detect */
50
+ readonly installSource?: InstallSource;
51
+ /**
52
+ * Override for "does the running closure already provide this package?".
53
+ * Production leaves it unset (real `require.resolve`); a spec sets it to
54
+ * reach the branch that still seeds `@camstack/system`, which is otherwise
55
+ * unreachable in a process where that package always resolves.
56
+ */
57
+ readonly isPackageResolvable?: (packageName: string) => boolean;
58
+ /**
59
+ * The server closure's node_modules to dedupe addon trees against.
60
+ * Production leaves it unset (derived from `CAMSTACK_FRAMEWORK_DIR`);
61
+ * specs point it at a fabricated closure dir.
62
+ */
63
+ readonly closureNodeModulesDir?: string;
66
64
  }
65
+ import type { InstalledPackage, IScopedLogger } from "@camstack/types";
66
+ import { AddonManifest } from "./addon-manifest.js";
67
67
  export type { InstalledPackage };
68
68
  /** Outcome of {@link AddonInstaller.ensureAddonRuntimeDeps}. */
69
69
  export interface EnsureAddonDepsResult {
70
- /** Installed addon packages examined. */
71
- readonly checked: number;
72
- /** `"<package>:<dep>"` entries satisfied by a new closure link — no npm. */
73
- readonly linked: readonly string[];
74
- /** Packages whose deps required an in-place npm install. */
75
- readonly reinstalled: readonly string[];
76
- /** Packages whose deps could not be ensured (logged loudly, boot continues). */
77
- readonly failed: readonly string[];
70
+ /** Installed addon packages examined. */
71
+ readonly checked: number;
72
+ /** `"<package>:<dep>"` entries satisfied by a new closure link — no npm. */
73
+ readonly linked: readonly string[];
74
+ /** Packages whose deps required an in-place npm install. */
75
+ readonly reinstalled: readonly string[];
76
+ /** Packages whose deps could not be ensured (logged loudly, boot continues). */
77
+ readonly failed: readonly string[];
78
78
  }
79
79
  /** Outcome of {@link AddonInstaller.sweepBackups}. Absolute paths. */
80
80
  export interface BackupSweepResult {
81
- /** Backup dirs reclaimed by the sweep. */
82
- readonly removed: readonly string[];
83
- /** Backup dirs deliberately retained (rollback target / last copy). */
84
- readonly kept: readonly string[];
81
+ /** Backup dirs reclaimed by the sweep. */
82
+ readonly removed: readonly string[];
83
+ /** Backup dirs deliberately retained (rollback target / last copy). */
84
+ readonly kept: readonly string[];
85
85
  }
86
86
  /**
87
- * A staging tree younger than this may belong to an install still running —
88
- * possibly in another process. Only older trees are residue worth sweeping.
89
- * Generous on purpose: an addon's runtime-dependency `npm install` on a slow
90
- * host is minutes, and the cost of leaving residue one deploy longer is disk,
91
- * while the cost of sweeping a live one is a FAILED deploy.
92
- */
87
+ * A staging tree younger than this may belong to an install still running —
88
+ * possibly in another process. Only older trees are residue worth sweeping.
89
+ * Generous on purpose: an addon's runtime-dependency `npm install` on a slow
90
+ * host is minutes, and the cost of leaving residue one deploy longer is disk,
91
+ * while the cost of sweeping a live one is a FAILED deploy.
92
+ */
93
93
  export declare const STAGING_RESIDUE_MIN_AGE_MS: number;
94
94
  export interface StagingEntryAge {
95
- readonly name: string;
96
- /** Age of the entry's mtime, in ms. */
97
- readonly ageMs: number;
95
+ readonly name: string;
96
+ /** Age of the entry's mtime, in ms. */
97
+ readonly ageMs: number;
98
98
  }
99
99
  /**
100
- * Pick the staging entries that are safe to delete.
101
- *
102
- * `installFromTgz` used to clear the WHOLE `.staging` root before creating its
103
- * own dir. Two deploys arriving within one install's lifetime — the normal case
104
- * when the hub propagates two packages back to back — meant the second one
105
- * deleted the first one's tree out from under its running `npm install`:
106
- *
107
- * npm error code ENOENT
108
- * npm error path …/.staging/install-14820-2026-08-07T12-28-28-875Z/package/package.json
109
- *
110
- * which the propagation then reported as `runtime dependency install failed`.
111
- * Observed on the Mac desktop agent and on little-unraid on 2026-08-07.
112
- *
113
- * So a sweep only removes what cannot be live: not a tree this process is
114
- * building, and not one young enough to belong to anybody's in-flight install.
115
- */
100
+ * Pick the staging entries that are safe to delete.
101
+ *
102
+ * `installFromTgz` used to clear the WHOLE `.staging` root before creating its
103
+ * own dir. Two deploys arriving within one install's lifetime — the normal case
104
+ * when the hub propagates two packages back to back — meant the second one
105
+ * deleted the first one's tree out from under its running `npm install`:
106
+ *
107
+ * npm error code ENOENT
108
+ * npm error path …/.staging/install-14820-2026-08-07T12-28-28-875Z/package/package.json
109
+ *
110
+ * which the propagation then reported as `runtime dependency install failed`.
111
+ * Observed on the Mac desktop agent and on little-unraid on 2026-08-07.
112
+ *
113
+ * So a sweep only removes what cannot be live: not a tree this process is
114
+ * building, and not one young enough to belong to anybody's in-flight install.
115
+ */
116
116
  export declare function selectSweepableStaging(entries: readonly StagingEntryAge[], inFlight: ReadonlySet<string>, minAgeMs?: number): readonly string[];
117
117
  export declare class AddonInstaller {
118
- readonly addonsDir: string;
119
- private readonly registry;
120
- readonly workspaceDir: string | undefined;
121
- readonly installSource: InstallSource;
122
- private readonly logger;
123
- private readonly isPackageResolvable?;
124
- /** Test seam — production resolves via `CAMSTACK_FRAMEWORK_DIR`. */
125
- private readonly closureNodeModulesDir;
126
- /**
127
- * Central manifest of installed addons. Tracks version + source +
128
- * timestamps + last-backup pointer per package, written atomically
129
- * after every install/uninstall. Replaces the legacy per-addon
130
- * `.install-source` markers (which we still write for backward
131
- * compatibility with code that reads them directly — see fs-utils
132
- * `getAddonInstallSource`).
133
- */
134
- readonly manifest: AddonManifest;
135
- /**
136
- * Basenames under `.staging` this process is currently building. Never swept
137
- * — see {@link selectSweepableStaging}.
138
- */
139
- private readonly inFlightStaging;
140
- constructor(config: AddonInstallerConfig, logger?: IScopedLogger);
141
- /**
142
- * Where a bootstrapped npm lives when the host has none on PATH (packaged
143
- * Electron agents ship a bare node binary). Persistent — sibling of the
144
- * installed addons, survives restarts, downloaded at most once per host.
145
- */
146
- private get npmCacheDir();
147
- /** Shared options for every npm invocation this installer performs. */
148
- private npmRunOptions;
149
- /**
150
- * Derive the bootstrap addon list from a meta-package's runtime dependencies.
151
- * Single source of truth: the meta-package's `package.json` declares which
152
- * `@camstack/addon-*` packages the deployment needs. Replaces previously
153
- * hardcoded lists — see design spec
154
- * docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
155
- */
156
- /**
157
- * Is `packageName` reachable through normal resolution — i.e. does the
158
- * running closure already provide it?
159
- *
160
- * Overridable via `AddonInstallerConfig.isPackageResolvable` so a spec can
161
- * exercise BOTH sides. That matters more than it looks: the branch that
162
- * still seeds is the one protecting a fresh deployment from an unbootable
163
- * node, and it is unreachable in a test process where `@camstack/system`
164
- * always resolves.
165
- */
166
- private isResolvableFromClosure;
167
- private static deriveBootstrapList;
168
- /**
169
- * Bootstrap packages installed on first boot — derived from the
170
- * `@camstack/server` meta-package's runtime dependencies. Adding a
171
- * bootstrap addon = adding it to `server/backend/package.json`.
172
- * See design spec
173
- * docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
174
- *
175
- * Camera provider drivers are NOT preinstalled with the hub — users
176
- * pick providers from the admin UI ("Install addon"). Saves ~80MB per
177
- * hub install and avoids shipping driver code unused on most hubs.
178
- */
179
- static readonly REQUIRED_PACKAGES: readonly string[];
180
- /**
181
- * Agent-only bootstrap packages — derived from the `@camstack/server`
182
- * meta-package's `camstack.agentBootstrapAddons` manifest field (single
183
- * source of truth; the separate agent meta-package is gone).
184
- * The agent runtime boots from the SAME `@camstack/server` closure, so its
185
- * bootstrap addon set is declared alongside the hub's. Adding an agent
186
- * bootstrap addon = adding it to `server/backend/package.json`'s
187
- * `camstack.agentBootstrapAddons`.
188
- */
189
- static readonly AGENT_PACKAGES: readonly string[];
190
- /**
191
- * Derive the agent bootstrap addon list from a meta-package's
192
- * `camstack.agentBootstrapAddons` manifest field, prepending
193
- * `@camstack/system` (the required infrastructure builtins carrier — same
194
- * rationale as `deriveBootstrapList`). Mirrors `deriveBootstrapList`'s
195
- * `require.resolve` nuance: the meta-package may be absent in a deployment
196
- * (this field is eagerly evaluated at class-load), so a failed resolve
197
- * yields an empty list rather than throwing.
198
- */
199
- private static deriveAgentBootstrapList;
200
- /**
201
- * Ensure all required packages are installed in the addons directory.
202
- *
203
- * Bootstrap-only — prefers the workspace/bundle copy when available
204
- * (offline-first, faster, container-self-contained). On-demand
205
- * installs from the admin UI go through `install()` instead, which
206
- * defaults to npm in production.
207
- *
208
- * There is no version argument and there is deliberately no pin: the system is
209
- * addons-agnostic and `latest` is the whole contract at first boot (operator,
210
- * 2026-08-13). A copy already under the addon root is never replaced either —
211
- * bootstrap is seed-only, and overwriting a deployed bundle would be an
212
- * un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
213
- *
214
- * @param packages — optional custom package list (default: REQUIRED_PACKAGES)
215
- */
216
- ensureRequiredPackages(packages?: readonly string[]): Promise<void>;
217
- /**
218
- * Reconcile the install manifest against the addons actually present on
219
- * disk: register seeded addons, correct a version that disagrees with the
220
- * installed `package.json`, and drop entries naming a directory that does
221
- * not exist. Call once after `ensureRequiredPackages`, before any update
222
- * can be in flight. See `AddonManifest.reconcileFromDisk` for the rules.
223
- *
224
- * Every correction is logged by name — a manifest that silently disagreed
225
- * with disk is what made "@camstack/system 1.2.29" read as installed on a
226
- * hub that deliberately has no copy of it.
227
- *
228
- * Returns the number of changes.
229
- */
230
- reconcileManifest(): number;
231
- /**
232
- * Make every INSTALLED addon's runtime dependencies resolvable — doing the
233
- * least work that achieves it. Runs at boot on hub and agent, which is what
234
- * turns a restore back into a working node: a system backup archives no
235
- * node_modules (D338), so before this pass every restored non-bootstrap
236
- * addon failed its first import until someone redeployed it by hand.
237
- *
238
- * Per addon, in order:
239
- * 1. drop closure links that no longer hold (dangling, or the closure
240
- * moved to a version the addon tree's recorded ranges refuse) — those
241
- * addons get a reinstall;
242
- * 2. a declared dep that already resolves in the addon tree costs nothing;
243
- * 3. a missing declared dep the closure provides at a COMPATIBLE version
244
- * becomes a link — no npm, no network;
245
- * 4. only an addon left with a genuinely unresolvable dep gets an npm
246
- * install (then dedupe + native ensure, same tail as a fresh install).
247
- *
248
- * "Only when necessary" is the contract: an addon whose deps are all
249
- * satisfied is not touched at all. Failures are per-addon and non-fatal —
250
- * a dep that cannot be re-fetched leaves that addon exactly as broken as
251
- * it already was, but LOUDLY, and never blocks the rest of the boot.
252
- */
253
- ensureAddonRuntimeDeps(): Promise<EnsureAddonDepsResult>;
254
- /**
255
- * One addon's dependency audit (steps 1–3 of `ensureAddonRuntimeDeps`).
256
- * Pure decision + link creation; the npm fallback is the caller's.
257
- */
258
- private ensureOneAddonDeps;
259
- /**
260
- * npm-install an installed addon's runtime deps IN PLACE (the restore /
261
- * repair path — the tree is not yet running at boot), then the same tail
262
- * every fresh install gets: closure dedupe + native deps + prebuild ensure.
263
- * Closure links are stripped first so npm reifies against plain missing
264
- * dirs instead of symlinks it does not own.
265
- */
266
- private reinstallAddonDeps;
267
- /**
268
- * Install a single addon — on-demand installer used by AddonPackageService
269
- * (admin UI "Install addon" / "Reinstall" buttons).
270
- *
271
- * Always npm. The legacy "auto-use workspace symlink in dev" branch
272
- * was removed; local development pushes via `camstack deploy` (CLI
273
- * tarball upload). Operators wanting to install from workspace use
274
- * `installFromWorkspace` (explicit `'local'` codepath) instead.
275
- */
276
- install(packageName: string, version?: string): Promise<{
277
- name: string;
278
- version: string;
279
- }>;
280
- /**
281
- * Install addon from a local workspace package. Two strategies
282
- * depending on `installSource`:
283
- * - `'symlink'` (dev): create a directory symlink
284
- * `addonsDir/<pkg>` → `<workspace>/packages/<pkg>`. Edits to
285
- * the workspace are visible at the next addon load after a
286
- * `npm run build` of that package — no copy step. Falls back
287
- * to `'local'` if symlink creation fails (Windows w/o
288
- * developer-mode).
289
- * - `'local'` (default): copy `package.json` (stripped) + `dist/`
290
- * into `addonsDir/<pkg>/`. The Electron bundled-addons path
291
- * uses this so the runtime owns its on-disk copy.
292
- */
293
- /**
294
- * Re-install one addon from the running server closure.
295
- *
296
- * The closure carries a copy of every addon it declares as a dependency, and
297
- * NOTHING loads an addon from there — `AddonLoader` reads the addon root and
298
- * only the addon root, on every role. So those copies are transport, and
299
- * this is the only thing that moves them into the place that runs code.
300
- *
301
- * Without it a server update advances the closure and changes nothing: six
302
- * addons on the hub were behind by up to nineteen versions on 2026-09-17,
303
- * each frozen at whenever somebody last ran `camstack deploy`.
304
- *
305
- * WHICH addons deserve this is not decided here — see `planAddonRealignment`,
306
- * which needs two gates because a version comparison alone would overwrite a
307
- * deliberate deploy. This only carries out a decision already made.
308
- */
309
- realignFromClosure(packageName: string, closureDir: string): Promise<{
310
- name: string;
311
- version: string;
312
- }>;
313
- private installLocal;
314
- /**
315
- * Symlink `addonsDir/<pkg>` at the workspace source dir. Dev-only.
316
- * After this, the AddonLoader resolves `<addonsDir>/<pkg>/dist/...`
317
- * through the symlink straight to `packages/<pkg>/dist/...` — a fresh
318
- * `npm run build` of the package is immediately picked up by the
319
- * next addon load.
320
- *
321
- * Auto-runs `ensureBuilt` so a workspace freshly cloned (with no
322
- * dist/ yet) still boots — same auto-build hook installCopy uses.
323
- *
324
- * Does NOT plant peer-dep symlinks into `<targetDir>/node_modules/`
325
- * the way the pre-`eb96df3c` symlink mode did. Self-contained
326
- * addons bundle their own copy of types/zod/sdk — no shared
327
- * workspace symlinks needed.
328
- */
329
- private installSymlink;
330
- private installCopy;
331
- /**
332
- * Install addon from npm (download tgz, then extract). Tries the
333
- * registry HTTPS API first (works inside packaged Electron — no need
334
- * for `npm` on PATH); falls back to `npm pack` for parity with the
335
- * legacy path when the registry call fails (private registries with
336
- * unusual auth, offline mode, etc).
337
- */
338
- installFromNpm(packageName: string, version?: string): Promise<{
339
- name: string;
340
- version: string;
341
- }>;
342
- /**
343
- * Resolve `{packageName, version?}` against the configured registry
344
- * over HTTPS and download the tarball into `tmpDir`. Returns the path
345
- * to the downloaded `.tgz`.
346
- *
347
- * Versioning rules (mirrors `npm pack` semantics):
348
- * - `version === undefined` → uses `dist-tags.latest`
349
- * - exact semver string → looked up in `versions[version]`
350
- * - dist-tag name (e.g. `next`, `beta`) → resolved via `dist-tags`
351
- *
352
- * Range specs (`^1.0.0`, `~1.2`, `>=2`) are NOT supported here — the
353
- * caller should resolve those upstream. `npm pack` handles them, so
354
- * the legacy fallback path remains the right answer for those.
355
- */
356
- private downloadNpmTarball;
357
- /**
358
- * Evict an existing install dir by atomic rename-aside, then best-effort
359
- * delete the aside copy.
360
- *
361
- * Why not a plain `fs.promises.rm(targetDir, {recursive})`: during a
362
- * `camstack deploy` the addon's live runner still holds its native
363
- * prebuilds (`.node`/`.so`) open. On the hub's shfs/FUSE `/data/addons`,
364
- * a recursive rm of a held subdir fails `ENOTEMPTY` mid-walk and leaves
365
- * the dir gutted. A rename only touches the dirent (metadata), so it
366
- * succeeds with the inodes still open — the old runner keeps its fds on
367
- * the moved inodes until it restarts.
368
- *
369
- * The aside copy is removed best-effort: the held native libs are only
370
- * released once the post-install `restartAddon` recycles the runner, so a
371
- * failure to delete it now must NOT fail the install. Any residue is swept
372
- * on the next deploy.
373
- */
374
- private evictInstallDir;
375
- /**
376
- * Best-effort removal of `.staging` residue left by a CRASHED earlier deploy.
377
- *
378
- * Deliberately not `sweepGraveyard`: an evicted `.evicting/*` dir is dead by
379
- * construction, but a `.staging/*` dir may be an install still running — in
380
- * this process or another one. Deleting one of those fails a live deploy with
381
- * an ENOENT on its own package.json, which is what happened on 2026-08-07.
382
- */
383
- private sweepStagingResidue;
384
- /** Best-effort removal of leftover `.evicting/*` dirs from earlier deploys. */
385
- private sweepGraveyard;
386
- /**
387
- * Make `pkgDir` (an addon tree that has NOT been swapped in yet) runnable:
388
- * strip the host-provided deps from its manifest, then `npm install` whatever
389
- * survives.
390
- *
391
- * ONE implementation for every path that materialises an addon tree —
392
- * `installFromTgz` (deploy/upload) and `applyUpdateFromStaged` (OTA). The OTA
393
- * path did not have it, and that is a whole outage class: an addon declaring
394
- * `camstack.runtimeDependencies` was broken by its FIRST OTA update, its dist
395
- * landing without `node_modules`. Every load then threw `Cannot find module`
396
- * and the retry loop replayed it — `@camstack/addon-export-hap`, 126 failed
397
- * load retries over 10.5h on 2026-08-12; `@camstack/addon-remote-storage`
398
- * (`@aws-sdk/*`, `webdav`) is the same landmine.
399
- *
400
- * **Strip.** `@camstack/*` are host-provided system packages that resolve via
401
- * the host's node_modules (Node walks up from the installed addon dir). Left
402
- * in, this `npm install` pulls the LAST PUBLISHED `@camstack/types` (etc.)
403
- * into the addon's OWN node_modules where it SHADOWS the host's fresh copy —
404
- * local additions to a system package silently never reach the deployed
405
- * addon. Addon dists are self-contained besides, so `stripBundledDeps` keeps
406
- * only what the manifest explicitly declares in
407
- * `camstack.runtimeDependencies` (see fs-utils / ADR-0027). Nothing left to
408
- * install is the COMMON case: skip npm rather than pay an empty round-trip.
409
- *
410
- * **Failure is FATAL.** This used to warn-and-continue on the tgz path ("the
411
- * addon may still load if imports are lazy") — live cost: a host with no npm
412
- * (packaged Electron Mac agent) installed every runtime-dep addon WITHOUT its
413
- * node_modules for DAYS; each reported "running" while its entry failed at
414
- * import (`Cannot find module 'sharp'`), the detection group ran 1/3 members,
415
- * and the node silently dropped out of the balancer. Throwing here is what
416
- * keeps the PREVIOUS install intact: every caller builds the tree before it
417
- * swaps, so an abort simply means the swap never happens.
418
- *
419
- * A missing/unreadable manifest is NOT fatal — it is logged and skipped. The
420
- * callers validate the tree themselves, and a tree with no readable
421
- * package.json has no declared deps to install (the loader will skip the
422
- * package entirely).
423
- */
424
- private installRuntimeDependencies;
425
- /**
426
- * Make `pkgDir`'s NATIVE modules loadable on THIS host, before it is swapped
427
- * in: install whatever `camstack.nativeDependencies` declares, then ensure
428
- * every traditional native present in the tree actually carries a compiled
429
- * `.node` for the running ABI.
430
- *
431
- * ONE implementation, for the same reason as {@link installRuntimeDependencies}
432
- * — every path that materialises an addon tree calls it, so no call site can
433
- * forget it. `installFromTgz` (deploy/upload) always ran these two steps; the
434
- * OTA staged-swap path ran NEITHER even after the runtime-dep fix (2026-08-12,
435
- * task #15, which named this gap explicitly). Same outage class one layer
436
- * down: an addon with native modules was broken by its FIRST OTA update, its
437
- * dist landing without an ABI-matched binary, and every load dying at the
438
- * binding (`Could not locate the bindings file`) — from the outside
439
- * indistinguishable from a bad bundle.
440
- *
441
- * **Two distinct steps, both load-bearing.**
442
- * `installManifestNativeDeps` fetches the DECLARED natives (prebuilt host copy
443
- * first — offline — then npm + an ABI rebuild), and is idempotent through a
444
- * content-hash marker. `ensureAddonNativePrebuilds` is the post-install pass:
445
- * npm can leave a traditional native (`better-sqlite3`) SOURCE-ONLY on a
446
- * toolchain-less host, so it re-fetches the prebuild for the running ABI and
447
- * THROWS naming module + addon if the binary is still absent. No bundled
448
- * source is available on this path (unlike `installCopy`) — fetch only.
449
- *
450
- * **Failure is FATAL**, mirroring the tgz path: callers complete the tree
451
- * BEFORE they swap, so an abort simply means the swap never happens and the
452
- * previous version keeps serving. Shipping a native-less copy instead would
453
- * trade one broken version for a crash-loop.
454
- *
455
- * A missing/unreadable manifest is logged and skipped — `installRuntimeDependencies`
456
- * has already said so loudly, and a tree with no readable package.json
457
- * declares no natives.
458
- */
459
- private installNativeDependencies;
460
- /**
461
- * Stop copying what the server closure already provides: replace each
462
- * top-level `node_modules` entry the closure serves at a COMPATIBLE version
463
- * with a symlink into the closure (see `deps/closure-dedupe.ts` for the
464
- * plan rules and the live measurements). Runs LAST in tree
465
- * materialisation — after the runtime-dep npm install AND the native-dep
466
- * steps — so no later npm invocation can fight the links.
467
- *
468
- * Non-fatal by design: dedupe is an optimisation, and its failure mode is
469
- * "the addon keeps its own copies", which is exactly today's behaviour. A
470
- * refusal on version grounds is logged loudly — that line is the answer to
471
- * "why does this addon still carry its own zod".
472
- */
473
- private dedupeTreeAgainstClosure;
474
- /** Install addon from a tgz file (uploaded or downloaded) */
475
- installFromTgz(tgzPath: string): Promise<{
476
- name: string;
477
- version: string;
478
- }>;
479
- /**
480
- * Apply an update to an installed addon, backing up the current
481
- * version first so the caller can roll back atomically on failure.
482
- *
483
- * Steps:
484
- * 1. Rename current install dir → {addonsDir}/.backups/{name}/{ts}/
485
- * 2. Run a fresh install (npm or local depending on installSource)
486
- * 3. Record `lastBackupDir` in the manifest entry
487
- * 4. Prune every OTHER backup of this addon — the previous one just
488
- * lost its only pointer and would otherwise be orphaned forever.
489
- *
490
- * The post-install caller (restart + health-check) is responsible for
491
- * verifying the new version actually works, and for calling either
492
- * `clearBackup()` on success or `rollbackAddon()` on failure. This
493
- * method must NOT delete the backup itself: at this point the new
494
- * version has not been proven to work.
495
- *
496
- * Throws if there is no installed version to update — caller should
497
- * prefer plain `install()` for first-time installs.
498
- */
499
- applyUpdate(packageName: string, version?: string): Promise<{
500
- name: string;
501
- version: string;
502
- backupDir: string;
503
- }>;
504
- /**
505
- * Apply an update from a pre-validated staged directory — the fast
506
- * swap-from-staged path that skips npm entirely.
507
- *
508
- * Mirrors `applyUpdate` exactly for backup/restore/manifest, but
509
- * replaces step 2 ("install new version") with an atomic directory
510
- * move of `stagedPath` into `addonDir`.
511
- *
512
- * "Skips npm entirely" is true only of the REGISTRY round-trip: the staged
513
- * tree is the raw unpacked tarball, so the addon's own
514
- * `camstack.runtimeDependencies` AND `camstack.nativeDependencies` still have
515
- * to be installed into it, exactly as `installFromTgz` does. Skipping the
516
- * first broke every runtime-dep addon on its first OTA update; skipping the
517
- * second broke every addon with a native module the same way, one layer down
518
- * (`Could not locate the bindings file` instead of `Cannot find module`) —
519
- * see {@link installRuntimeDependencies} and {@link installNativeDependencies}.
520
- *
521
- * Order matters and is `installFromTgz`'s: the tree is COMPLETED FIRST, and
522
- * the live install is only then backed up and replaced. So the addon keeps
523
- * serving the old version for the whole (minutes-long) npm install, the swap
524
- * window stays two renames wide, and a dependency failure aborts with the
525
- * previous version untouched instead of leaving a dependency-less copy live.
526
- *
527
- * On cross-device move (EXDEV) falls back to a recursive copy followed
528
- * by removal of the staged directory. On any swap failure the backup is
529
- * restored and the error is rethrown — identical recovery to `applyUpdate`.
530
- *
531
- * Throws if the package is not tracked in the manifest, if `addonDir`
532
- * is missing (same preconditions as `applyUpdate`), or if the runtime-dep /
533
- * native-dep install fails.
534
- */
535
- applyUpdateFromStaged(packageName: string, version: string, stagedPath: string): Promise<{
536
- name: string;
537
- version: string;
538
- backupDir: string;
539
- }>;
540
- /**
541
- * Roll back an addon to its most recent backup. Used after an update
542
- * passes installation but fails its post-restart health check.
543
- *
544
- * Returns the version that was restored, or `null` if there was no
545
- * backup to roll back to.
546
- */
547
- rollbackAddon(packageName: string): Promise<string | null>;
548
- /** Root of the pre-update rollback copies: `{addonsDir}/.backups`. */
549
- private get backupsRoot();
550
- /**
551
- * True only when `target` resolves to something strictly INSIDE
552
- * `{addonsDir}/.backups/`.
553
- *
554
- * Every deletion in this section funnels through here. `lastBackupDir`
555
- * is read back from a manifest file on disk — an operator edit, a
556
- * restored manifest from another host, or a `..` in the recorded path
557
- * must never turn "reclaim a backup" into "delete the live install".
558
- */
559
- private isInsideBackups;
560
- /**
561
- * Best-effort removal of one path under `.backups/`.
562
- *
563
- * Never throws: an undeleted backup is a disk-space problem, whereas a
564
- * throw on the post-update success path would turn a working update into
565
- * a reported outage. Returns true only when the path is gone.
566
- */
567
- private removeBackupPath;
568
- /** List the timestamped backup dirs recorded for one package. */
569
- private listBackupsFor;
570
- /**
571
- * Keep at most ONE backup per addon: drop every backup dir for
572
- * `packageName` except `keepDir`.
573
- *
574
- * Called right after a new backup is recorded. Without this, a second
575
- * update overwrites `lastBackupDir` and the previous backup becomes
576
- * unreachable — no pointer, so neither `rollbackAddon` nor `clearBackup`
577
- * can ever see it again. That is how the live hub accumulated two 398 MiB
578
- * copies of one addon. Never throws.
579
- */
580
- private pruneBackups;
581
- /** Drop `.backups/{pkg}` (and its `@scope` parent) once they are empty. */
582
- private removeEmptyBackupDirs;
583
- /**
584
- * Drop the recorded backup for an addon — call once the post-update
585
- * health check confirms the new version actually works.
586
- *
587
- * Never throws and never rejects. The manifest pointer is cleared even
588
- * when the bytes could not be removed: a pointer at a half-deleted tree
589
- * would make `rollbackAddon` restore a gutted install, and the boot sweep
590
- * reclaims the residue on the next start.
591
- */
592
- clearBackup(packageName: string): Promise<void>;
593
- /**
594
- * Boot-time retention sweep over `{addonsDir}/.backups/`.
595
- *
596
- * RULE: for each addon, the ONLY backup that survives is the one the
597
- * manifest's `lastBackupDir` points at — everything else is unreachable
598
- * by construction (no pointer ⇒ neither `rollbackAddon` nor `clearBackup`
599
- * can ever reach it). One exception: when the addon's LIVE install dir is
600
- * missing, the newest backup is the only surviving copy of that addon (a
601
- * crash between the rename-aside and the manifest write in `applyUpdate`),
602
- * so it is kept instead of reclaimed.
603
- *
604
- * Why not "delete everything once the addon is healthy": this installer
605
- * has no health signal, and the pointed-at backup is precisely the one a
606
- * failed update left for the operator's Rollback button. Bounding to one
607
- * per addon is enough — the observed 814 MiB was duplicate copies, not a
608
- * single retained rollback target.
609
- *
610
- * Never throws. Safe to run on every boot; runs before any update can be
611
- * in flight.
612
- */
613
- sweepBackups(): Promise<BackupSweepResult>;
614
- /**
615
- * Which backup of `packageName` survives the sweep: the manifest's
616
- * rollback target, or — when the live install is gone — the newest copy,
617
- * which is then the only one that exists. `null` means "reclaim them all".
618
- */
619
- private resolveBackupToKeep;
620
- /** Package names that have a `.backups/{pkg}` directory, scoped or not. */
621
- private listBackedUpPackages;
622
- uninstall(packageName: string): Promise<void>;
623
- listInstalled(): InstalledPackage[];
624
- isInstalled(packageName: string): boolean;
625
- getInstalledPackage(packageName: string): InstalledPackage | null;
626
- private findLocalPackage;
627
- /** Ensure a package is built (dist/ exists and page bundles present) */
628
- private ensureBuilt;
629
- /** Check if page bundles declared in package.json are missing from dist/ */
630
- private isDistIncomplete;
118
+ readonly addonsDir: string;
119
+ private readonly registry;
120
+ readonly workspaceDir: string | undefined;
121
+ readonly installSource: InstallSource;
122
+ private readonly logger;
123
+ private readonly isPackageResolvable?;
124
+ /** Test seam — production resolves via `CAMSTACK_FRAMEWORK_DIR`. */
125
+ private readonly closureNodeModulesDir;
126
+ /**
127
+ * Central manifest of installed addons. Tracks version + source +
128
+ * timestamps + last-backup pointer per package, written atomically
129
+ * after every install/uninstall. Replaces the legacy per-addon
130
+ * `.install-source` markers (which we still write for backward
131
+ * compatibility with code that reads them directly — see fs-utils
132
+ * `getAddonInstallSource`).
133
+ */
134
+ readonly manifest: AddonManifest;
135
+ /**
136
+ * Basenames under `.staging` this process is currently building. Never swept
137
+ * — see {@link selectSweepableStaging}.
138
+ */
139
+ private readonly inFlightStaging;
140
+ constructor(config: AddonInstallerConfig, logger?: IScopedLogger);
141
+ /**
142
+ * Where a bootstrapped npm lives when the host has none on PATH (packaged
143
+ * Electron agents ship a bare node binary). Persistent — sibling of the
144
+ * installed addons, survives restarts, downloaded at most once per host.
145
+ */
146
+ private get npmCacheDir();
147
+ /** Shared options for every npm invocation this installer performs. */
148
+ private npmRunOptions;
149
+ /**
150
+ * Derive the bootstrap addon list from a meta-package's runtime dependencies.
151
+ * Single source of truth: the meta-package's `package.json` declares which
152
+ * `@camstack/addon-*` packages the deployment needs. Replaces previously
153
+ * hardcoded lists — see design spec
154
+ * docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
155
+ */
156
+ /**
157
+ * Is `packageName` reachable through normal resolution — i.e. does the
158
+ * running closure already provide it?
159
+ *
160
+ * Overridable via `AddonInstallerConfig.isPackageResolvable` so a spec can
161
+ * exercise BOTH sides. That matters more than it looks: the branch that
162
+ * still seeds is the one protecting a fresh deployment from an unbootable
163
+ * node, and it is unreachable in a test process where `@camstack/system`
164
+ * always resolves.
165
+ */
166
+ private isResolvableFromClosure;
167
+ private static deriveBootstrapList;
168
+ /**
169
+ * Bootstrap packages installed on first boot — derived from the
170
+ * `@camstack/server` meta-package's runtime dependencies. Adding a
171
+ * bootstrap addon = adding it to `server/backend/package.json`.
172
+ * See design spec
173
+ * docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
174
+ *
175
+ * Camera provider drivers are NOT preinstalled with the hub — users
176
+ * pick providers from the admin UI ("Install addon"). Saves ~80MB per
177
+ * hub install and avoids shipping driver code unused on most hubs.
178
+ */
179
+ static readonly REQUIRED_PACKAGES: readonly string[];
180
+ /**
181
+ * Agent-only bootstrap packages — derived from the `@camstack/server`
182
+ * meta-package's `camstack.agentBootstrapAddons` manifest field (single
183
+ * source of truth; the separate agent meta-package is gone).
184
+ * The agent runtime boots from the SAME `@camstack/server` closure, so its
185
+ * bootstrap addon set is declared alongside the hub's. Adding an agent
186
+ * bootstrap addon = adding it to `server/backend/package.json`'s
187
+ * `camstack.agentBootstrapAddons`.
188
+ */
189
+ static readonly AGENT_PACKAGES: readonly string[];
190
+ /**
191
+ * Derive the agent bootstrap addon list from a meta-package's
192
+ * `camstack.agentBootstrapAddons` manifest field, prepending
193
+ * `@camstack/system` (the required infrastructure builtins carrier — same
194
+ * rationale as `deriveBootstrapList`). Mirrors `deriveBootstrapList`'s
195
+ * `require.resolve` nuance: the meta-package may be absent in a deployment
196
+ * (this field is eagerly evaluated at class-load), so a failed resolve
197
+ * yields an empty list rather than throwing.
198
+ */
199
+ private static deriveAgentBootstrapList;
200
+ /**
201
+ * Ensure all required packages are installed in the addons directory.
202
+ *
203
+ * Bootstrap-only — prefers the workspace/bundle copy when available
204
+ * (offline-first, faster, container-self-contained). On-demand
205
+ * installs from the admin UI go through `install()` instead, which
206
+ * defaults to npm in production.
207
+ *
208
+ * There is no version argument and there is deliberately no pin: the system is
209
+ * addons-agnostic and `latest` is the whole contract at first boot (operator,
210
+ * 2026-08-13). A copy already under the addon root is never replaced either —
211
+ * bootstrap is seed-only, and overwriting a deployed bundle would be an
212
+ * un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
213
+ *
214
+ * @param packages — optional custom package list (default: REQUIRED_PACKAGES)
215
+ */
216
+ ensureRequiredPackages(packages?: readonly string[]): Promise<void>;
217
+ /**
218
+ * Reconcile the install manifest against the addons actually present on
219
+ * disk: register seeded addons, correct a version that disagrees with the
220
+ * installed `package.json`, and drop entries naming a directory that does
221
+ * not exist. Call once after `ensureRequiredPackages`, before any update
222
+ * can be in flight. See `AddonManifest.reconcileFromDisk` for the rules.
223
+ *
224
+ * Every correction is logged by name — a manifest that silently disagreed
225
+ * with disk is what made "@camstack/system 1.2.29" read as installed on a
226
+ * hub that deliberately has no copy of it.
227
+ *
228
+ * Returns the number of changes.
229
+ */
230
+ reconcileManifest(): number;
231
+ /**
232
+ * Make every INSTALLED addon's runtime dependencies resolvable — doing the
233
+ * least work that achieves it. Runs at boot on hub and agent, which is what
234
+ * turns a restore back into a working node: a system backup archives no
235
+ * node_modules (D338), so before this pass every restored non-bootstrap
236
+ * addon failed its first import until someone redeployed it by hand.
237
+ *
238
+ * Per addon, in order:
239
+ * 1. drop closure links that no longer hold (dangling, or the closure
240
+ * moved to a version the addon tree's recorded ranges refuse) — those
241
+ * addons get a reinstall;
242
+ * 2. a declared dep that already resolves in the addon tree costs nothing;
243
+ * 3. a missing declared dep the closure provides at a COMPATIBLE version
244
+ * becomes a link — no npm, no network;
245
+ * 4. only an addon left with a genuinely unresolvable dep gets an npm
246
+ * install (then dedupe + native ensure, same tail as a fresh install).
247
+ *
248
+ * "Only when necessary" is the contract: an addon whose deps are all
249
+ * satisfied is not touched at all. Failures are per-addon and non-fatal —
250
+ * a dep that cannot be re-fetched leaves that addon exactly as broken as
251
+ * it already was, but LOUDLY, and never blocks the rest of the boot.
252
+ */
253
+ ensureAddonRuntimeDeps(): Promise<EnsureAddonDepsResult>;
254
+ /**
255
+ * One addon's dependency audit (steps 1–3 of `ensureAddonRuntimeDeps`).
256
+ * Pure decision + link creation; the npm fallback is the caller's.
257
+ */
258
+ private ensureOneAddonDeps;
259
+ /**
260
+ * npm-install an installed addon's runtime deps IN PLACE (the restore /
261
+ * repair path — the tree is not yet running at boot), then the same tail
262
+ * every fresh install gets: closure dedupe + native deps + prebuild ensure.
263
+ * Closure links are stripped first so npm reifies against plain missing
264
+ * dirs instead of symlinks it does not own.
265
+ */
266
+ private reinstallAddonDeps;
267
+ /**
268
+ * Install a single addon — on-demand installer used by AddonPackageService
269
+ * (admin UI "Install addon" / "Reinstall" buttons).
270
+ *
271
+ * Always npm. The legacy "auto-use workspace symlink in dev" branch
272
+ * was removed; local development pushes via `camstack deploy` (CLI
273
+ * tarball upload). Operators wanting to install from workspace use
274
+ * `installFromWorkspace` (explicit `'local'` codepath) instead.
275
+ */
276
+ install(packageName: string, version?: string): Promise<{
277
+ name: string;
278
+ version: string;
279
+ }>;
280
+ /**
281
+ * Install addon from a local workspace package. Two strategies
282
+ * depending on `installSource`:
283
+ * - `'symlink'` (dev): create a directory symlink
284
+ * `addonsDir/<pkg>` → `<workspace>/packages/<pkg>`. Edits to
285
+ * the workspace are visible at the next addon load after a
286
+ * `npm run build` of that package — no copy step. Falls back
287
+ * to `'local'` if symlink creation fails (Windows w/o
288
+ * developer-mode).
289
+ * - `'local'` (default): copy `package.json` (stripped) + `dist/`
290
+ * into `addonsDir/<pkg>/`. The Electron bundled-addons path
291
+ * uses this so the runtime owns its on-disk copy.
292
+ */
293
+ /**
294
+ * Re-install one addon from the running server closure.
295
+ *
296
+ * The closure carries a copy of every addon it declares as a dependency, and
297
+ * NOTHING loads an addon from there — `AddonLoader` reads the addon root and
298
+ * only the addon root, on every role. So those copies are transport, and
299
+ * this is the only thing that moves them into the place that runs code.
300
+ *
301
+ * Without it a server update advances the closure and changes nothing: six
302
+ * addons on the hub were behind by up to nineteen versions on 2026-09-17,
303
+ * each frozen at whenever somebody last ran `camstack deploy`.
304
+ *
305
+ * WHICH addons deserve this is not decided here — see `planAddonRealignment`,
306
+ * which needs two gates because a version comparison alone would overwrite a
307
+ * deliberate deploy. This only carries out a decision already made.
308
+ */
309
+ realignFromClosure(packageName: string, closureDir: string): Promise<{
310
+ name: string;
311
+ version: string;
312
+ }>;
313
+ private installLocal;
314
+ /**
315
+ * Symlink `addonsDir/<pkg>` at the workspace source dir. Dev-only.
316
+ * After this, the AddonLoader resolves `<addonsDir>/<pkg>/dist/...`
317
+ * through the symlink straight to `packages/<pkg>/dist/...` — a fresh
318
+ * `npm run build` of the package is immediately picked up by the
319
+ * next addon load.
320
+ *
321
+ * Auto-runs `ensureBuilt` so a workspace freshly cloned (with no
322
+ * dist/ yet) still boots — same auto-build hook installCopy uses.
323
+ *
324
+ * Does NOT plant peer-dep symlinks into `<targetDir>/node_modules/`
325
+ * the way the pre-`eb96df3c` symlink mode did. Self-contained
326
+ * addons bundle their own copy of types/zod/sdk — no shared
327
+ * workspace symlinks needed.
328
+ */
329
+ private installSymlink;
330
+ private installCopy;
331
+ /**
332
+ * Install addon from npm (download tgz, then extract). Tries the
333
+ * registry HTTPS API first (works inside packaged Electron — no need
334
+ * for `npm` on PATH); falls back to `npm pack` for parity with the
335
+ * legacy path when the registry call fails (private registries with
336
+ * unusual auth, offline mode, etc).
337
+ */
338
+ installFromNpm(packageName: string, version?: string): Promise<{
339
+ name: string;
340
+ version: string;
341
+ }>;
342
+ /**
343
+ * Resolve `{packageName, version?}` against the configured registry
344
+ * over HTTPS and download the tarball into `tmpDir`. Returns the path
345
+ * to the downloaded `.tgz`.
346
+ *
347
+ * Versioning rules (mirrors `npm pack` semantics):
348
+ * - `version === undefined` → uses `dist-tags.latest`
349
+ * - exact semver string → looked up in `versions[version]`
350
+ * - dist-tag name (e.g. `next`, `beta`) → resolved via `dist-tags`
351
+ *
352
+ * Range specs (`^1.0.0`, `~1.2`, `>=2`) are NOT supported here — the
353
+ * caller should resolve those upstream. `npm pack` handles them, so
354
+ * the legacy fallback path remains the right answer for those.
355
+ */
356
+ private downloadNpmTarball;
357
+ /**
358
+ * Evict an existing install dir by atomic rename-aside, then best-effort
359
+ * delete the aside copy.
360
+ *
361
+ * Why not a plain `fs.promises.rm(targetDir, {recursive})`: during a
362
+ * `camstack deploy` the addon's live runner still holds its native
363
+ * prebuilds (`.node`/`.so`) open. On the hub's shfs/FUSE `/data/addons`,
364
+ * a recursive rm of a held subdir fails `ENOTEMPTY` mid-walk and leaves
365
+ * the dir gutted. A rename only touches the dirent (metadata), so it
366
+ * succeeds with the inodes still open — the old runner keeps its fds on
367
+ * the moved inodes until it restarts.
368
+ *
369
+ * The aside copy is removed best-effort: the held native libs are only
370
+ * released once the post-install `restartAddon` recycles the runner, so a
371
+ * failure to delete it now must NOT fail the install. Any residue is swept
372
+ * on the next deploy.
373
+ */
374
+ private evictInstallDir;
375
+ /**
376
+ * Best-effort removal of `.staging` residue left by a CRASHED earlier deploy.
377
+ *
378
+ * Deliberately not `sweepGraveyard`: an evicted `.evicting/*` dir is dead by
379
+ * construction, but a `.staging/*` dir may be an install still running — in
380
+ * this process or another one. Deleting one of those fails a live deploy with
381
+ * an ENOENT on its own package.json, which is what happened on 2026-08-07.
382
+ */
383
+ private sweepStagingResidue;
384
+ /** Best-effort removal of leftover `.evicting/*` dirs from earlier deploys. */
385
+ private sweepGraveyard;
386
+ /**
387
+ * Make `pkgDir` (an addon tree that has NOT been swapped in yet) runnable:
388
+ * strip the host-provided deps from its manifest, then `npm install` whatever
389
+ * survives.
390
+ *
391
+ * ONE implementation for every path that materialises an addon tree —
392
+ * `installFromTgz` (deploy/upload) and `applyUpdateFromStaged` (OTA). The OTA
393
+ * path did not have it, and that is a whole outage class: an addon declaring
394
+ * `camstack.runtimeDependencies` was broken by its FIRST OTA update, its dist
395
+ * landing without `node_modules`. Every load then threw `Cannot find module`
396
+ * and the retry loop replayed it — `@camstack/addon-export-hap`, 126 failed
397
+ * load retries over 10.5h on 2026-08-12; `@camstack/addon-remote-storage`
398
+ * (`@aws-sdk/*`, `webdav`) is the same landmine.
399
+ *
400
+ * **Strip.** `@camstack/*` are host-provided system packages that resolve via
401
+ * the host's node_modules (Node walks up from the installed addon dir). Left
402
+ * in, this `npm install` pulls the LAST PUBLISHED `@camstack/types` (etc.)
403
+ * into the addon's OWN node_modules where it SHADOWS the host's fresh copy —
404
+ * local additions to a system package silently never reach the deployed
405
+ * addon. Addon dists are self-contained besides, so `stripBundledDeps` keeps
406
+ * only what the manifest explicitly declares in
407
+ * `camstack.runtimeDependencies` (see fs-utils / ADR-0027). Nothing left to
408
+ * install is the COMMON case: skip npm rather than pay an empty round-trip.
409
+ *
410
+ * **Failure is FATAL.** This used to warn-and-continue on the tgz path ("the
411
+ * addon may still load if imports are lazy") — live cost: a host with no npm
412
+ * (packaged Electron Mac agent) installed every runtime-dep addon WITHOUT its
413
+ * node_modules for DAYS; each reported "running" while its entry failed at
414
+ * import (`Cannot find module 'sharp'`), the detection group ran 1/3 members,
415
+ * and the node silently dropped out of the balancer. Throwing here is what
416
+ * keeps the PREVIOUS install intact: every caller builds the tree before it
417
+ * swaps, so an abort simply means the swap never happens.
418
+ *
419
+ * A missing/unreadable manifest is NOT fatal — it is logged and skipped. The
420
+ * callers validate the tree themselves, and a tree with no readable
421
+ * package.json has no declared deps to install (the loader will skip the
422
+ * package entirely).
423
+ */
424
+ private installRuntimeDependencies;
425
+ /**
426
+ * Make `pkgDir`'s NATIVE modules loadable on THIS host, before it is swapped
427
+ * in: install whatever `camstack.nativeDependencies` declares, then ensure
428
+ * every traditional native present in the tree actually carries a compiled
429
+ * `.node` for the running ABI.
430
+ *
431
+ * ONE implementation, for the same reason as {@link installRuntimeDependencies}
432
+ * — every path that materialises an addon tree calls it, so no call site can
433
+ * forget it. `installFromTgz` (deploy/upload) always ran these two steps; the
434
+ * OTA staged-swap path ran NEITHER even after the runtime-dep fix (2026-08-12,
435
+ * task #15, which named this gap explicitly). Same outage class one layer
436
+ * down: an addon with native modules was broken by its FIRST OTA update, its
437
+ * dist landing without an ABI-matched binary, and every load dying at the
438
+ * binding (`Could not locate the bindings file`) — from the outside
439
+ * indistinguishable from a bad bundle.
440
+ *
441
+ * **Two distinct steps, both load-bearing.**
442
+ * `installManifestNativeDeps` fetches the DECLARED natives (prebuilt host copy
443
+ * first — offline — then npm + an ABI rebuild), and is idempotent through a
444
+ * content-hash marker. `ensureAddonNativePrebuilds` is the post-install pass:
445
+ * npm can leave a traditional native (`better-sqlite3`) SOURCE-ONLY on a
446
+ * toolchain-less host, so it re-fetches the prebuild for the running ABI and
447
+ * THROWS naming module + addon if the binary is still absent. No bundled
448
+ * source is available on this path (unlike `installCopy`) — fetch only.
449
+ *
450
+ * **Failure is FATAL**, mirroring the tgz path: callers complete the tree
451
+ * BEFORE they swap, so an abort simply means the swap never happens and the
452
+ * previous version keeps serving. Shipping a native-less copy instead would
453
+ * trade one broken version for a crash-loop.
454
+ *
455
+ * A missing/unreadable manifest is logged and skipped — `installRuntimeDependencies`
456
+ * has already said so loudly, and a tree with no readable package.json
457
+ * declares no natives.
458
+ */
459
+ private installNativeDependencies;
460
+ /**
461
+ * Stop copying what the server closure already provides: replace each
462
+ * top-level `node_modules` entry the closure serves at a COMPATIBLE version
463
+ * with a symlink into the closure (see `deps/closure-dedupe.ts` for the
464
+ * plan rules and the live measurements). Runs LAST in tree
465
+ * materialisation — after the runtime-dep npm install AND the native-dep
466
+ * steps — so no later npm invocation can fight the links.
467
+ *
468
+ * Non-fatal by design: dedupe is an optimisation, and its failure mode is
469
+ * "the addon keeps its own copies", which is exactly today's behaviour. A
470
+ * refusal on version grounds is logged loudly — that line is the answer to
471
+ * "why does this addon still carry its own zod".
472
+ */
473
+ private dedupeTreeAgainstClosure;
474
+ /** Install addon from a tgz file (uploaded or downloaded) */
475
+ installFromTgz(tgzPath: string): Promise<{
476
+ name: string;
477
+ version: string;
478
+ }>;
479
+ /**
480
+ * Apply an update to an installed addon, backing up the current
481
+ * version first so the caller can roll back atomically on failure.
482
+ *
483
+ * Steps:
484
+ * 1. Rename current install dir → {addonsDir}/.backups/{name}/{ts}/
485
+ * 2. Run a fresh install (npm or local depending on installSource)
486
+ * 3. Record `lastBackupDir` in the manifest entry
487
+ * 4. Prune every OTHER backup of this addon — the previous one just
488
+ * lost its only pointer and would otherwise be orphaned forever.
489
+ *
490
+ * The post-install caller (restart + health-check) is responsible for
491
+ * verifying the new version actually works, and for calling either
492
+ * `clearBackup()` on success or `rollbackAddon()` on failure. This
493
+ * method must NOT delete the backup itself: at this point the new
494
+ * version has not been proven to work.
495
+ *
496
+ * Throws if there is no installed version to update — caller should
497
+ * prefer plain `install()` for first-time installs.
498
+ */
499
+ applyUpdate(packageName: string, version?: string): Promise<{
500
+ name: string;
501
+ version: string;
502
+ backupDir: string;
503
+ }>;
504
+ /**
505
+ * Apply an update from a pre-validated staged directory — the fast
506
+ * swap-from-staged path that skips npm entirely.
507
+ *
508
+ * Mirrors `applyUpdate` exactly for backup/restore/manifest, but
509
+ * replaces step 2 ("install new version") with an atomic directory
510
+ * move of `stagedPath` into `addonDir`.
511
+ *
512
+ * "Skips npm entirely" is true only of the REGISTRY round-trip: the staged
513
+ * tree is the raw unpacked tarball, so the addon's own
514
+ * `camstack.runtimeDependencies` AND `camstack.nativeDependencies` still have
515
+ * to be installed into it, exactly as `installFromTgz` does. Skipping the
516
+ * first broke every runtime-dep addon on its first OTA update; skipping the
517
+ * second broke every addon with a native module the same way, one layer down
518
+ * (`Could not locate the bindings file` instead of `Cannot find module`) —
519
+ * see {@link installRuntimeDependencies} and {@link installNativeDependencies}.
520
+ *
521
+ * Order matters and is `installFromTgz`'s: the tree is COMPLETED FIRST, and
522
+ * the live install is only then backed up and replaced. So the addon keeps
523
+ * serving the old version for the whole (minutes-long) npm install, the swap
524
+ * window stays two renames wide, and a dependency failure aborts with the
525
+ * previous version untouched instead of leaving a dependency-less copy live.
526
+ *
527
+ * On cross-device move (EXDEV) falls back to a recursive copy followed
528
+ * by removal of the staged directory. On any swap failure the backup is
529
+ * restored and the error is rethrown — identical recovery to `applyUpdate`.
530
+ *
531
+ * Throws if the package is not tracked in the manifest, if `addonDir`
532
+ * is missing (same preconditions as `applyUpdate`), or if the runtime-dep /
533
+ * native-dep install fails.
534
+ */
535
+ applyUpdateFromStaged(packageName: string, version: string, stagedPath: string): Promise<{
536
+ name: string;
537
+ version: string;
538
+ backupDir: string;
539
+ }>;
540
+ /**
541
+ * Roll back an addon to its most recent backup. Used after an update
542
+ * passes installation but fails its post-restart health check.
543
+ *
544
+ * Returns the version that was restored, or `null` if there was no
545
+ * backup to roll back to.
546
+ */
547
+ rollbackAddon(packageName: string): Promise<string | null>;
548
+ /** Root of the pre-update rollback copies: `{addonsDir}/.backups`. */
549
+ private get backupsRoot();
550
+ /**
551
+ * True only when `target` resolves to something strictly INSIDE
552
+ * `{addonsDir}/.backups/`.
553
+ *
554
+ * Every deletion in this section funnels through here. `lastBackupDir`
555
+ * is read back from a manifest file on disk — an operator edit, a
556
+ * restored manifest from another host, or a `..` in the recorded path
557
+ * must never turn "reclaim a backup" into "delete the live install".
558
+ */
559
+ private isInsideBackups;
560
+ /**
561
+ * Best-effort removal of one path under `.backups/`.
562
+ *
563
+ * Never throws: an undeleted backup is a disk-space problem, whereas a
564
+ * throw on the post-update success path would turn a working update into
565
+ * a reported outage. Returns true only when the path is gone.
566
+ */
567
+ private removeBackupPath;
568
+ /** List the timestamped backup dirs recorded for one package. */
569
+ private listBackupsFor;
570
+ /**
571
+ * Keep at most ONE backup per addon: drop every backup dir for
572
+ * `packageName` except `keepDir`.
573
+ *
574
+ * Called right after a new backup is recorded. Without this, a second
575
+ * update overwrites `lastBackupDir` and the previous backup becomes
576
+ * unreachable — no pointer, so neither `rollbackAddon` nor `clearBackup`
577
+ * can ever see it again. That is how the live hub accumulated two 398 MiB
578
+ * copies of one addon. Never throws.
579
+ */
580
+ private pruneBackups;
581
+ /** Drop `.backups/{pkg}` (and its `@scope` parent) once they are empty. */
582
+ private removeEmptyBackupDirs;
583
+ /**
584
+ * Drop the recorded backup for an addon — call once the post-update
585
+ * health check confirms the new version actually works.
586
+ *
587
+ * Never throws and never rejects. The manifest pointer is cleared even
588
+ * when the bytes could not be removed: a pointer at a half-deleted tree
589
+ * would make `rollbackAddon` restore a gutted install, and the boot sweep
590
+ * reclaims the residue on the next start.
591
+ */
592
+ clearBackup(packageName: string): Promise<void>;
593
+ /**
594
+ * Boot-time retention sweep over `{addonsDir}/.backups/`.
595
+ *
596
+ * RULE: for each addon, the ONLY backup that survives is the one the
597
+ * manifest's `lastBackupDir` points at — everything else is unreachable
598
+ * by construction (no pointer ⇒ neither `rollbackAddon` nor `clearBackup`
599
+ * can ever reach it). One exception: when the addon's LIVE install dir is
600
+ * missing, the newest backup is the only surviving copy of that addon (a
601
+ * crash between the rename-aside and the manifest write in `applyUpdate`),
602
+ * so it is kept instead of reclaimed.
603
+ *
604
+ * Why not "delete everything once the addon is healthy": this installer
605
+ * has no health signal, and the pointed-at backup is precisely the one a
606
+ * failed update left for the operator's Rollback button. Bounding to one
607
+ * per addon is enough — the observed 814 MiB was duplicate copies, not a
608
+ * single retained rollback target.
609
+ *
610
+ * Never throws. Safe to run on every boot; runs before any update can be
611
+ * in flight.
612
+ */
613
+ sweepBackups(): Promise<BackupSweepResult>;
614
+ /**
615
+ * Which backup of `packageName` survives the sweep: the manifest's
616
+ * rollback target, or — when the live install is gone — the newest copy,
617
+ * which is then the only one that exists. `null` means "reclaim them all".
618
+ */
619
+ private resolveBackupToKeep;
620
+ /** Package names that have a `.backups/{pkg}` directory, scoped or not. */
621
+ private listBackedUpPackages;
622
+ uninstall(packageName: string): Promise<void>;
623
+ listInstalled(): InstalledPackage[];
624
+ isInstalled(packageName: string): boolean;
625
+ getInstalledPackage(packageName: string): InstalledPackage | null;
626
+ private findLocalPackage;
627
+ /** Ensure a package is built (dist/ exists and page bundles present) */
628
+ private ensureBuilt;
629
+ /** Check if page bundles declared in package.json are missing from dist/ */
630
+ private isDistIncomplete;
631
631
  }