@ceralive/modem-control 1.0.0 → 1.2.0

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 (480) hide show
  1. package/README.md +341 -0
  2. package/dist/backend/at-lease.d.ts +59 -0
  3. package/dist/backend/at-lease.js +118 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +101 -0
  61. package/dist/backend/transition-preconditions.js +132 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +216 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +20 -0
  146. package/dist/index.js +27 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +61 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operation-ids.d.ts +2 -0
  196. package/dist/operation-ids.js +26 -0
  197. package/dist/operations/contracts.d.ts +72 -0
  198. package/dist/operations/contracts.js +1 -0
  199. package/dist/operations/index.d.ts +1 -0
  200. package/dist/operations/index.js +1 -0
  201. package/dist/operations/operation-engine.d.ts +16 -0
  202. package/dist/operations/operation-engine.js +194 -0
  203. package/dist/ports/index.d.ts +12 -0
  204. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  205. package/dist/ports/location.d.ts +87 -0
  206. package/dist/ports/location.js +36 -0
  207. package/dist/ports/modem-manager.d.ts +89 -0
  208. package/dist/ports/modem-manager.js +9 -0
  209. package/dist/ports/mutation-admission.d.ts +27 -0
  210. package/dist/ports/mutation-admission.js +9 -0
  211. package/dist/ports/network-manager.d.ts +68 -0
  212. package/dist/ports/network-manager.js +13 -0
  213. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  214. package/dist/ports/observation.js +7 -0
  215. package/dist/ports/ops.d.ts +44 -0
  216. package/dist/ports/ops.js +16 -0
  217. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  218. package/dist/ports/receipts.js +9 -0
  219. package/dist/ports/reconcile.d.ts +33 -0
  220. package/dist/ports/reconcile.js +200 -0
  221. package/dist/ports/resource-ownership.d.ts +29 -0
  222. package/dist/ports/resource-ownership.js +1 -0
  223. package/dist/ports/router.d.ts +19 -0
  224. package/dist/ports/router.js +7 -0
  225. package/dist/ports/sms.d.ts +64 -0
  226. package/dist/ports/sms.js +24 -0
  227. package/dist/ports/uhubctl.d.ts +6 -0
  228. package/dist/ports/uhubctl.js +1 -0
  229. package/dist/providers/contracts.d.ts +124 -0
  230. package/dist/providers/contracts.js +10 -0
  231. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  232. package/dist/providers/huawei-hilink/index.js +2 -0
  233. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  234. package/dist/providers/huawei-hilink/operations.js +56 -0
  235. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  236. package/dist/providers/huawei-hilink/provider.js +76 -0
  237. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  238. package/dist/providers/huawei-hilink/runtime.js +171 -0
  239. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  240. package/dist/providers/huawei-hilink/session.js +120 -0
  241. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  242. package/dist/providers/huawei-hilink/transport.js +1 -0
  243. package/dist/providers/index.d.ts +8 -0
  244. package/dist/providers/index.js +8 -0
  245. package/dist/providers/matcher.d.ts +3 -0
  246. package/dist/providers/matcher.js +205 -0
  247. package/dist/providers/modem-manager/errors.d.ts +7 -0
  248. package/dist/providers/modem-manager/errors.js +37 -0
  249. package/dist/providers/modem-manager/generic-operations.d.ts +10 -0
  250. package/dist/providers/modem-manager/generic-operations.js +209 -0
  251. package/dist/providers/modem-manager/index.d.ts +4 -0
  252. package/dist/providers/modem-manager/index.js +4 -0
  253. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  254. package/dist/providers/modem-manager/module-operations.js +118 -0
  255. package/dist/providers/modem-manager/provider.d.ts +41 -0
  256. package/dist/providers/modem-manager/provider.js +155 -0
  257. package/dist/providers/modem-manager/runtime-composition-operation.d.ts +32 -0
  258. package/dist/providers/modem-manager/runtime-composition-operation.js +151 -0
  259. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  260. package/dist/providers/modem-manager/snapshot.js +204 -0
  261. package/dist/providers/modem-manager/types.d.ts +137 -0
  262. package/dist/providers/modem-manager/types.js +1 -0
  263. package/dist/providers/network-manager/adapter.d.ts +71 -0
  264. package/dist/providers/network-manager/adapter.js +348 -0
  265. package/dist/providers/network-manager/index.d.ts +2 -0
  266. package/dist/providers/network-manager/index.js +2 -0
  267. package/dist/providers/network-manager/types.d.ts +171 -0
  268. package/dist/providers/network-manager/types.js +77 -0
  269. package/dist/providers/registry.d.ts +13 -0
  270. package/dist/providers/registry.js +33 -0
  271. package/dist/providers/ufi-himi/index.d.ts +6 -0
  272. package/dist/providers/ufi-himi/index.js +6 -0
  273. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  274. package/dist/providers/ufi-himi/operations.js +66 -0
  275. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  276. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  277. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  278. package/dist/providers/ufi-himi/provider.js +204 -0
  279. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  280. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  281. package/dist/providers/ufi-himi/session.d.ts +46 -0
  282. package/dist/providers/ufi-himi/session.js +92 -0
  283. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  284. package/dist/providers/ufi-himi/transport.js +25 -0
  285. package/dist/providers/zte-goform/index.d.ts +2 -0
  286. package/dist/providers/zte-goform/index.js +2 -0
  287. package/dist/providers/zte-goform/provider.d.ts +56 -0
  288. package/dist/providers/zte-goform/provider.js +101 -0
  289. package/dist/providers/zte-goform/session.d.ts +23 -0
  290. package/dist/providers/zte-goform/session.js +197 -0
  291. package/dist/providers/zte-goform/transport.d.ts +16 -0
  292. package/dist/providers/zte-goform/transport.js +1 -0
  293. package/dist/radio/band-truth.d.ts +50 -0
  294. package/dist/radio/band-truth.js +92 -0
  295. package/dist/radio/index.d.ts +3 -0
  296. package/dist/radio/index.js +10 -0
  297. package/dist/radio/mode-combinations.d.ts +88 -0
  298. package/dist/radio/mode-combinations.js +198 -0
  299. package/dist/radio/mode-truth.d.ts +67 -0
  300. package/dist/radio/mode-truth.js +112 -0
  301. package/dist/redact.d.ts +15 -0
  302. package/dist/redact.js +189 -0
  303. package/dist/safety/composition-root.d.ts +28 -0
  304. package/dist/safety/composition-root.js +65 -0
  305. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  306. package/dist/safety/flock-resource-ownership.js +138 -0
  307. package/dist/safety/index.d.ts +2 -0
  308. package/dist/safety/index.js +2 -0
  309. package/dist/sms/dbus-messaging.d.ts +17 -0
  310. package/dist/sms/dbus-messaging.js +185 -0
  311. package/dist/sms/inbox-store.d.ts +10 -0
  312. package/dist/sms/inbox-store.js +82 -0
  313. package/dist/sms/index.d.ts +4 -0
  314. package/dist/sms/index.js +10 -0
  315. package/dist/sms/mmcli-parse.d.ts +54 -0
  316. package/dist/sms/mmcli-parse.js +224 -0
  317. package/dist/sms/normalize.d.ts +42 -0
  318. package/dist/sms/normalize.js +95 -0
  319. package/dist/testing/domain-fakes.d.ts +58 -0
  320. package/dist/testing/domain-fakes.js +98 -0
  321. package/dist/testing/index.d.ts +2 -0
  322. package/dist/testing/index.js +17 -0
  323. package/dist/testing/provider-fakes.d.ts +45 -0
  324. package/dist/testing/provider-fakes.js +64 -0
  325. package/dist/transport/calls.d.ts +9 -0
  326. package/dist/transport/calls.js +88 -0
  327. package/dist/transport/codec.d.ts +3 -0
  328. package/dist/transport/codec.js +207 -0
  329. package/dist/transport/dbus-native.d.ts +57 -0
  330. package/dist/transport/dbus-native.js +17 -0
  331. package/dist/transport/errors.d.ts +21 -0
  332. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  333. package/dist/transport/index.d.ts +4 -0
  334. package/dist/transport/index.js +9 -0
  335. package/dist/transport/signals.d.ts +15 -0
  336. package/dist/transport/signals.js +123 -0
  337. package/dist/transport/signature.d.ts +7 -0
  338. package/dist/transport/signature.js +94 -0
  339. package/dist/transport/transport.d.ts +2 -0
  340. package/dist/transport/transport.js +202 -0
  341. package/dist/transport/types.d.ts +61 -0
  342. package/dist/transport/types.js +19 -0
  343. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  344. package/dist/usb-mode/catalog-schema.js +97 -0
  345. package/dist/usb-mode/catalog.d.ts +21 -0
  346. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  347. package/dist/usb-mode/certified-catalog.json +67 -0
  348. package/dist/usb-mode/index.d.ts +6 -0
  349. package/dist/usb-mode/index.js +16 -0
  350. package/dist/usb-mode/ingestion.d.ts +111 -0
  351. package/dist/usb-mode/ingestion.js +187 -0
  352. package/dist/usb-mode/promotion-review.d.ts +21 -0
  353. package/dist/usb-mode/promotion-review.js +87 -0
  354. package/dist/usb-mode/runtime-capability.d.ts +59 -0
  355. package/dist/usb-mode/runtime-capability.js +157 -0
  356. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  357. package/dist/usb-mode/usb-devices-parse.js +157 -0
  358. package/dist/ussd/calls.d.ts +32 -0
  359. package/dist/ussd/calls.js +96 -0
  360. package/dist/ussd/index.d.ts +5 -0
  361. package/dist/ussd/index.js +12 -0
  362. package/dist/ussd/mm-ussd.d.ts +37 -0
  363. package/dist/ussd/mm-ussd.js +205 -0
  364. package/dist/ussd/refusal.d.ts +53 -0
  365. package/dist/ussd/refusal.js +154 -0
  366. package/dist/ussd/registration.d.ts +20 -0
  367. package/dist/ussd/registration.js +101 -0
  368. package/dist/ussd/session.d.ts +106 -0
  369. package/dist/ussd/session.js +163 -0
  370. package/package.json +38 -4
  371. package/src/backend/at-lease.test.ts +0 -106
  372. package/src/backend/at-lease.ts +0 -158
  373. package/src/backend/cell-info.test.ts +0 -154
  374. package/src/backend/cell-info.ts +0 -160
  375. package/src/backend/device-classifier.test.ts +0 -168
  376. package/src/backend/device-classifier.ts +0 -248
  377. package/src/backend/enrichment.ts +0 -96
  378. package/src/backend/features.test.ts +0 -162
  379. package/src/backend/features.ts +0 -179
  380. package/src/backend/identity-ladder.test.ts +0 -117
  381. package/src/backend/identity-ladder.ts +0 -221
  382. package/src/backend/identity-registry.test.ts +0 -89
  383. package/src/backend/identity-registry.ts +0 -151
  384. package/src/backend/index.ts +0 -236
  385. package/src/backend/lifecycle-interlock.ts +0 -38
  386. package/src/backend/managed-objects.ts +0 -108
  387. package/src/backend/mapping.ts +0 -160
  388. package/src/backend/mm-backend.ts +0 -191
  389. package/src/backend/mm-mutations.ts +0 -228
  390. package/src/backend/modem-actor.test.ts +0 -95
  391. package/src/backend/modem-actor.ts +0 -112
  392. package/src/backend/nm-auto-apn.ts +0 -161
  393. package/src/backend/nm-gsm-fields.ts +0 -122
  394. package/src/backend/nmcli-nm-port.ts +0 -228
  395. package/src/backend/nmcli-runner.ts +0 -52
  396. package/src/backend/observer.ts +0 -297
  397. package/src/backend/power-contract.test.ts +0 -40
  398. package/src/backend/power-contract.ts +0 -83
  399. package/src/backend/recovery-attribution.test.ts +0 -102
  400. package/src/backend/recovery-attribution.ts +0 -86
  401. package/src/backend/recovery-budget.test.ts +0 -64
  402. package/src/backend/recovery-budget.ts +0 -84
  403. package/src/backend/recovery-ladder.test.ts +0 -257
  404. package/src/backend/recovery-ladder.ts +0 -249
  405. package/src/backend/router-ethernet.test.ts +0 -71
  406. package/src/backend/router-ethernet.ts +0 -90
  407. package/src/backend/row-store.ts +0 -105
  408. package/src/backend/signal-setup.ts +0 -112
  409. package/src/backend/sim-unlock.ts +0 -193
  410. package/src/backend/transition-preconditions.ts +0 -149
  411. package/src/backend/uhubctl-power-hook.test.ts +0 -274
  412. package/src/backend/uhubctl-power-hook.ts +0 -377
  413. package/src/backend/usage/accounting.test.ts +0 -147
  414. package/src/backend/usage/accounting.ts +0 -123
  415. package/src/backend/usage/billing-cycle.test.ts +0 -62
  416. package/src/backend/usage/billing-cycle.ts +0 -45
  417. package/src/backend/usage/index.ts +0 -60
  418. package/src/backend/usage/policy-store.test.ts +0 -164
  419. package/src/backend/usage/policy-store.ts +0 -216
  420. package/src/backend/usage/policy-write.test.ts +0 -198
  421. package/src/backend/usage/policy-write.ts +0 -207
  422. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  423. package/src/backend/usage/sampler.test.ts +0 -327
  424. package/src/backend/usage/sampler.ts +0 -282
  425. package/src/backend/usage/store.test.ts +0 -148
  426. package/src/backend/usage/store.ts +0 -177
  427. package/src/backend/usb-enumerator.test.ts +0 -87
  428. package/src/backend/usb-enumerator.ts +0 -181
  429. package/src/backend/usb-mode-transition.test.ts +0 -323
  430. package/src/backend/usb-mode-transition.ts +0 -253
  431. package/src/domain/brand.ts +0 -29
  432. package/src/domain/errors.ts +0 -77
  433. package/src/domain/guards.test.ts +0 -218
  434. package/src/domain/guards.ts +0 -144
  435. package/src/domain/identity.test.ts +0 -83
  436. package/src/domain/identity.ts +0 -165
  437. package/src/domain/index.ts +0 -12
  438. package/src/domain/snapshot.test.ts +0 -266
  439. package/src/domain/snapshot.ts +0 -120
  440. package/src/index.test.ts +0 -6
  441. package/src/index.ts +0 -15
  442. package/src/ports/README.md +0 -61
  443. package/src/ports/forbidden-surface.test.ts +0 -241
  444. package/src/ports/modem-manager.ts +0 -72
  445. package/src/ports/network-manager.ts +0 -87
  446. package/src/ports/ops.ts +0 -60
  447. package/src/ports/ops.type-test.ts +0 -39
  448. package/src/ports/receipts.test.ts +0 -153
  449. package/src/ports/reconcile.test.ts +0 -152
  450. package/src/ports/reconcile.ts +0 -338
  451. package/src/ports/router.ts +0 -29
  452. package/src/redact.test.ts +0 -82
  453. package/src/redact.ts +0 -73
  454. package/src/transport/README.md +0 -65
  455. package/src/transport/calls.ts +0 -113
  456. package/src/transport/characterization.test.ts +0 -260
  457. package/src/transport/codec.test.ts +0 -118
  458. package/src/transport/codec.ts +0 -240
  459. package/src/transport/conformance-python.test.ts +0 -152
  460. package/src/transport/conformance-same-lib.test.ts +0 -115
  461. package/src/transport/dbus-native-lib.d.ts +0 -19
  462. package/src/transport/dbus-native.ts +0 -85
  463. package/src/transport/index.ts +0 -30
  464. package/src/transport/no-library-leak.test.ts +0 -61
  465. package/src/transport/reliability.test.ts +0 -173
  466. package/src/transport/signals.ts +0 -150
  467. package/src/transport/signature.ts +0 -110
  468. package/src/transport/test-support/fake-service.ts +0 -168
  469. package/src/transport/test-support/independent-producer.py +0 -110
  470. package/src/transport/test-support/private-bus.ts +0 -66
  471. package/src/transport/transport.ts +0 -250
  472. package/src/transport/types.ts +0 -118
  473. package/src/usb-mode/catalog-schema.test.ts +0 -181
  474. package/src/usb-mode/catalog-schema.ts +0 -113
  475. package/src/usb-mode/certified-catalog.json +0 -67
  476. package/src/usb-mode/index.ts +0 -58
  477. package/src/usb-mode/ingestion.test.ts +0 -268
  478. package/src/usb-mode/ingestion.ts +0 -297
  479. package/src/usb-mode/promotion-review.ts +0 -117
  480. package/src/usb-mode/usb-devices-parse.ts +0 -196
@@ -0,0 +1,68 @@
1
+ // The claims every router admin API makes identically, in one place.
2
+ //
3
+ // HiLink, goform and HIMI are three vendor HTTP surfaces over a modem, and they share
4
+ // a capability boundary: none of them exposes ModemManager's modem state, its 3GPP
5
+ // registration enum, its lock enum or its SIM-type enum. Those read `unsupported`,
6
+ // which is a durable claim about the SOURCE rather than about one poll — and stating
7
+ // it once here is what stops the three normalizers from drifting into three different
8
+ // answers for the same structural fact.
9
+ //
10
+ // SIM PRESENCE is deliberately NOT claimed. Each vendor reports a presence code of
11
+ // its own (`SimStatus`, `simcard_state`, `simstate`) with vendor semantics, and no
12
+ // migrated decoder covers them; guessing one would be exactly the invented reading
13
+ // this layer exists to prevent. It reads `not-reported` and the vendor code stays
14
+ // verbatim in the diagnostics block for the per-vendor providers to claim later.
15
+ import { isUninformativeIdentity, modemHardwareLabel, modemHardwareName, } from '../../domain/index.js';
16
+ import { knownMetric, unknownMetric } from '../metric.js';
17
+ export function unsupportedRadioMetric(provenance) {
18
+ return unknownMetric('unsupported', provenance([]));
19
+ }
20
+ /**
21
+ * The SIM block every router source produces.
22
+ *
23
+ * `vendorPresenceField` NAMES the vendor's own presence code when the payload carried
24
+ * one, so the evidence records that a code exists and was deliberately not decoded —
25
+ * distinct from `no-evidence`, which says the payload offered nothing at all. Neither
26
+ * one is ever `absent`: claiming absence from a vendor code whose semantics no
27
+ * migrated decoder covers is precisely the invented reading this layer refuses.
28
+ */
29
+ export function routerSim(provenance, vendorPresenceField) {
30
+ // The vendor field is NAMED in the evidence but is NOT consumed: no metric claims its
31
+ // value, so it must stay in the diagnostics block's `unmapped` set, verbatim, for the
32
+ // per-vendor provider that will one day decode it with evidence.
33
+ return {
34
+ presence: unknownMetric('not-reported', provenance([])),
35
+ presenceEvidence: vendorPresenceField === undefined
36
+ ? { kind: 'no-evidence', inspected: [] }
37
+ : { kind: 'vendor-code-unclaimed', field: vendorPresenceField },
38
+ lockRequired: unknownMetric('unsupported', provenance([])),
39
+ kind: unknownMetric('unsupported', provenance([])),
40
+ esimStatus: unknownMetric('unsupported', provenance([])),
41
+ };
42
+ }
43
+ /** Router admin APIs report no measurement-recency flag; that is a source capability claim. */
44
+ export function unsupportedQualityRecent(provenance) {
45
+ return unknownMetric('unsupported', provenance([]));
46
+ }
47
+ /**
48
+ * A router's product name, screened by the migrated presentation rules.
49
+ *
50
+ * `modemHardwareLabel` falls back to a generic label when its input says nothing, and
51
+ * publishing that as a KNOWN value would be reporting a name no device gave. So an
52
+ * uninformative product string is refused up front and reads `not-reported` instead.
53
+ */
54
+ export function routerHardware(provenance, product) {
55
+ if (product === undefined || isUninformativeIdentity(product.name)) {
56
+ const source = provenance(product === undefined ? [] : [product.field]);
57
+ return {
58
+ label: unknownMetric('not-reported', source),
59
+ displayName: unknownMetric('not-reported', source),
60
+ };
61
+ }
62
+ const source = provenance([product.field]);
63
+ const identity = { model: product.name };
64
+ return {
65
+ label: knownMetric(modemHardwareLabel(identity), source),
66
+ displayName: knownMetric(modemHardwareName(identity), source),
67
+ };
68
+ }
@@ -0,0 +1,10 @@
1
+ import type { ObservationEnvelope } from '../../domain/index.js';
2
+ import { type NormalizationContext } from '../envelope.js';
3
+ import type { NormalizedModemObservation } from '../model.js';
4
+ export type UfiObservationInput = {
5
+ readonly sysinfo: string;
6
+ readonly overview: string;
7
+ readonly status: string;
8
+ readonly produceInfo?: string;
9
+ };
10
+ export declare function normalizeUfiObservation(input: UfiObservationInput, context: NormalizationContext): ObservationEnvelope<NormalizedModemObservation>;
@@ -0,0 +1,111 @@
1
+ // Qualcomm UFI / HIMI → normalized observation.
2
+ //
3
+ // UFI answers three endpoints per read, each an envelope of its own (`{reply, params}`),
4
+ // and the migrated `parseUfiSignal` already folds them in the vendor's own precedence
5
+ // order. This module keeps all three bodies verbatim — including the `reply` field,
6
+ // which is how a `SessionOut` refusal is told apart from a body that simply lacked the
7
+ // key — and reports the ONE signal reading the source actually provides.
8
+ //
9
+ // Its overview endpoint returns an IMSI and an ICCID. They are retained, because
10
+ // normalization does not get to decide what a diagnostician may need, and they are
11
+ // masked by the shared key-based redactor on the way to anything that renders. That
12
+ // split — retain here, redact at the boundary — is why `raw` is documented as a
13
+ // redaction-class surface rather than as safe-by-default data.
14
+ import { parseUfiDetails, parseUfiSignal } from '../../hardware/router-parsers.js';
15
+ import { freshObservation, metricProvenance } from '../envelope.js';
16
+ import { metricFromRouterSignal, unknownMetric } from '../metric.js';
17
+ import { createObservationDiagnostics, } from '../provenance.js';
18
+ import { hasRawField, mergeRawRecords, normalizeRawValue, parseJsonObject, prefixRawRecord, rawKey, } from '../raw.js';
19
+ import { routerHardware, routerSim, unsupportedQualityRecent, unsupportedRadioMetric, } from './router-shared.js';
20
+ const SOURCE = 'ufi-himiapi';
21
+ const SYSINFO = 'sysinfo';
22
+ const OVERVIEW = 'overview';
23
+ const STATUS = 'status';
24
+ const PRODUCE_INFO = 'produce-info';
25
+ const SESSION_REFUSAL = 'SessionOut';
26
+ /** HIMI's own SIM presence code. Named as evidence, never decoded into a presence. */
27
+ const SIM_STATE = rawKey(SYSINFO, 'simstate');
28
+ export function normalizeUfiObservation(input, context) {
29
+ const bodies = [
30
+ [SYSINFO, input.sysinfo],
31
+ [OVERVIEW, input.overview],
32
+ [STATUS, input.status],
33
+ [PRODUCE_INFO, input.produceInfo ?? ''],
34
+ ];
35
+ const notes = [];
36
+ const records = bodies.map(([name, text]) => {
37
+ const parsed = parseJsonObject(text);
38
+ if (parsed === undefined && text.trim() !== '') {
39
+ notes.push({ code: 'unparseable-body', field: name });
40
+ }
41
+ if (parsed?.reply === SESSION_REFUSAL) {
42
+ notes.push({ code: 'auth-expired', field: rawKey(name, 'reply') });
43
+ }
44
+ return prefixRawRecord(name, flattenUfiEnvelope(parsed));
45
+ });
46
+ const raw = mergeRawRecords(...records);
47
+ const consumed = [];
48
+ const provenance = (fields, authority) => {
49
+ consumed.push(...fields);
50
+ return authority === undefined
51
+ ? metricProvenance(SOURCE, context, fields)
52
+ : metricProvenance(SOURCE, context, fields, authority);
53
+ };
54
+ const signalModel = parseUfiSignal({
55
+ sysinfo: input.sysinfo,
56
+ overview: input.overview,
57
+ status: input.status,
58
+ });
59
+ const details = parseUfiDetails({
60
+ overview: input.overview,
61
+ sysinfo: input.sysinfo,
62
+ ...(input.produceInfo === undefined ? {} : { produceInfo: input.produceInfo }),
63
+ });
64
+ const product = details?.product;
65
+ return freshObservation(SOURCE, context, {
66
+ source: SOURCE,
67
+ hardware: routerHardware(provenance, product === undefined
68
+ ? undefined
69
+ : { name: product, field: rawKey(PRODUCE_INFO, 'productname') }),
70
+ radio: {
71
+ modemState: unsupportedRadioMetric(provenance),
72
+ registration: unsupportedRadioMetric(provenance),
73
+ accessTechnologies: unknownMetric('unsupported', provenance([])),
74
+ modeLabel: unknownMetric('not-reported', provenance([])),
75
+ },
76
+ signal: {
77
+ quality: unknownMetric('unsupported', provenance([])),
78
+ qualityRecent: unsupportedQualityRecent(provenance),
79
+ bars: metricFromRouterSignal(signalModel.bars, provenance([])),
80
+ maxBars: metricFromRouterSignal(signalModel.max_bars, provenance([])),
81
+ dbm: metricFromRouterSignal(signalModel.dbm, provenance([
82
+ rawKey(SYSINFO, 'SIGNAL'),
83
+ rawKey(OVERVIEW, 'SIGNAL'),
84
+ rawKey(STATUS, 'signalStrength'),
85
+ ])),
86
+ rsrp: metricFromRouterSignal(signalModel.rsrp, provenance([])),
87
+ rsrq: metricFromRouterSignal(signalModel.rsrq, provenance([])),
88
+ snr: metricFromRouterSignal(signalModel.snr, provenance([])),
89
+ sinr: metricFromRouterSignal(signalModel.sinr, provenance([])),
90
+ },
91
+ sim: routerSim(provenance, hasRawField(raw, SIM_STATE) ? SIM_STATE : undefined),
92
+ diagnostics: createObservationDiagnostics({ source: SOURCE, raw, consumed, notes }),
93
+ });
94
+ }
95
+ /** `{reply, params}` flattened to one level — `params` members keep their own names. */
96
+ function flattenUfiEnvelope(parsed) {
97
+ const out = {};
98
+ if (parsed === undefined) {
99
+ return out;
100
+ }
101
+ for (const [key, value] of Object.entries(parsed)) {
102
+ if (key === 'params' && typeof value === 'object' && value !== null && !Array.isArray(value)) {
103
+ for (const [field, param] of Object.entries(value)) {
104
+ out[field] = normalizeRawValue(param);
105
+ }
106
+ continue;
107
+ }
108
+ out[key] = normalizeRawValue(value);
109
+ }
110
+ return out;
111
+ }
@@ -0,0 +1,7 @@
1
+ import type { ObservationEnvelope } from '../../domain/index.js';
2
+ import { type NormalizationContext } from '../envelope.js';
3
+ import type { NormalizedModemObservation } from '../model.js';
4
+ export type ZteObservationInput = {
5
+ readonly body: string;
6
+ };
7
+ export declare function normalizeZteObservation(input: ZteObservationInput, context: NormalizationContext): ObservationEnvelope<NormalizedModemObservation>;
@@ -0,0 +1,71 @@
1
+ // ZTE goform → normalized observation.
2
+ //
3
+ // One goform response answers many keys at once, so the migrated `parseZteSignal` and
4
+ // `parseZteDetails` are both driven from the SAME body here — and everything neither
5
+ // of them claims (`wan_lte_ca`, `rmcc`, `lte_pci`, the cell id, the roaming flag) is
6
+ // retained verbatim in the diagnostics block. That retention is the point: a
7
+ // carrier-aggregation flag no normalized field has a slot for is still the difference
8
+ // between a diagnosable report and a shrug.
9
+ //
10
+ // A body that will not parse is an OBSERVATION whose metrics are `malformed`, not an
11
+ // unavailable one. The bytes arrived; what failed was decoding them, and an
12
+ // unavailable envelope would have to discard them to say so.
13
+ import { parseZteDetails, parseZteSignal } from '../../hardware/router-parsers.js';
14
+ import { freshObservation, metricProvenance } from '../envelope.js';
15
+ import { knownMetric, metricFromRouterSignal, unknownMetric, } from '../metric.js';
16
+ import { createObservationDiagnostics } from '../provenance.js';
17
+ import { hasRawField, parseJsonRecord, prefixRawRecord, rawKey } from '../raw.js';
18
+ import { routerHardware, routerSim, unsupportedQualityRecent, unsupportedRadioMetric, } from './router-shared.js';
19
+ const SOURCE = 'zte-goform';
20
+ const BODY = 'goform';
21
+ /** ZTE's own SIM presence code. Named as evidence, never decoded into a presence. */
22
+ const SIM_CARD_STATE = rawKey(BODY, 'simcard_state');
23
+ export function normalizeZteObservation(input, context) {
24
+ const parsed = parseJsonRecord(input.body);
25
+ const raw = prefixRawRecord(BODY, parsed);
26
+ const notes = [];
27
+ if (parsed === undefined) {
28
+ notes.push({ code: input.body.trim() === '' ? 'empty-body' : 'unparseable-body', field: BODY });
29
+ }
30
+ const consumed = [];
31
+ const provenance = (fields, authority) => {
32
+ consumed.push(...fields);
33
+ return authority === undefined
34
+ ? metricProvenance(SOURCE, context, fields)
35
+ : metricProvenance(SOURCE, context, fields, authority);
36
+ };
37
+ const signalModel = parseZteSignal(input.body);
38
+ const details = parseZteDetails(input.body);
39
+ return freshObservation(SOURCE, context, {
40
+ source: SOURCE,
41
+ hardware: routerHardware(provenance, undefined),
42
+ radio: {
43
+ modemState: unsupportedRadioMetric(provenance),
44
+ registration: unsupportedRadioMetric(provenance),
45
+ accessTechnologies: unknownMetric('unsupported', provenance([])),
46
+ modeLabel: normalizeModeLabel(details?.network_type, parsed !== undefined, provenance),
47
+ },
48
+ signal: {
49
+ quality: unknownMetric('unsupported', provenance([])),
50
+ qualityRecent: unsupportedQualityRecent(provenance),
51
+ bars: metricFromRouterSignal(signalModel.bars, provenance([rawKey(BODY, 'signalbar')], 'derived')),
52
+ // The goform payload carries no maximum; the migrated parser states the
53
+ // vendor's fixed five-bar scale, which is a derivation and says so.
54
+ maxBars: metricFromRouterSignal(signalModel.max_bars, provenance([], 'derived')),
55
+ dbm: metricFromRouterSignal(signalModel.dbm, provenance([rawKey(BODY, 'rssi')])),
56
+ rsrp: metricFromRouterSignal(signalModel.rsrp, provenance([rawKey(BODY, 'lte_rsrp')])),
57
+ rsrq: metricFromRouterSignal(signalModel.rsrq, provenance([rawKey(BODY, 'lte_rsrq')])),
58
+ snr: metricFromRouterSignal(signalModel.snr, provenance([rawKey(BODY, 'lte_snr')])),
59
+ sinr: metricFromRouterSignal(signalModel.sinr, provenance([])),
60
+ },
61
+ sim: routerSim(provenance, hasRawField(raw, SIM_CARD_STATE) ? SIM_CARD_STATE : undefined),
62
+ diagnostics: createObservationDiagnostics({ source: SOURCE, raw, consumed, notes }),
63
+ });
64
+ }
65
+ function normalizeModeLabel(networkType, parsed, provenance) {
66
+ const source = provenance([rawKey(BODY, 'network_type')]);
67
+ if (networkType !== undefined) {
68
+ return knownMetric(networkType, source);
69
+ }
70
+ return unknownMetric(parsed ? 'not-reported' : 'malformed', source);
71
+ }
@@ -0,0 +1,64 @@
1
+ import type { DeviceGeneration, EpochMillis, ObservationEnvelope } from '../domain/index.js';
2
+ /** What an operator asked for. Not a claim that anything acted on it. */
3
+ export type DesiredProfile<T> = {
4
+ readonly kind: 'desired';
5
+ readonly profile: T;
6
+ readonly requestedAt: EpochMillis;
7
+ /** Opaque origin label (an RPC caller, a policy engine). Never a credential. */
8
+ readonly requestedBy: string;
9
+ };
10
+ /** What was actually put into force, and by which operation, in which generation. */
11
+ export type AppliedConfiguration<T> = {
12
+ readonly kind: 'applied';
13
+ readonly configuration: T;
14
+ readonly appliedAt: EpochMillis;
15
+ readonly generation: DeviceGeneration;
16
+ readonly operationId: string;
17
+ };
18
+ /** What the device itself reports — always through an envelope, never bare. */
19
+ export type ObservedState<T> = {
20
+ readonly kind: 'observed';
21
+ readonly observation: ObservationEnvelope<T>;
22
+ };
23
+ export declare function desiredProfile<T>(profile: T, requestedAt: EpochMillis, requestedBy: string): DesiredProfile<T>;
24
+ export declare function appliedConfiguration<T>(input: {
25
+ readonly configuration: T;
26
+ readonly appliedAt: EpochMillis;
27
+ readonly generation: DeviceGeneration;
28
+ readonly operationId: string;
29
+ }): AppliedConfiguration<T>;
30
+ export declare function observedState<T>(observation: ObservationEnvelope<T>): ObservedState<T>;
31
+ /**
32
+ * The three-slot view. There is deliberately no fourth field holding a merged
33
+ * "effective" value: an effective value is a RENDERING decision, and computing one
34
+ * here would bake a policy every consumer would then have to work around.
35
+ */
36
+ export type ModemStateView<TDesired, TApplied, TObserved> = {
37
+ readonly desired: DesiredProfile<TDesired> | null;
38
+ readonly applied: AppliedConfiguration<TApplied> | null;
39
+ readonly observed: ObservedState<TObserved>;
40
+ };
41
+ export declare const STATE_VIEW_SLOTS: readonly ['desired', 'applied', 'observed'];
42
+ export type StateViewSlot = (typeof STATE_VIEW_SLOTS)[number];
43
+ export type SlotComparison = {
44
+ readonly status: 'aligned';
45
+ } | {
46
+ readonly status: 'diverged';
47
+ }
48
+ /** One side has nothing to compare — NOT the same as agreeing. */
49
+ | {
50
+ readonly status: 'indeterminate';
51
+ readonly missing: StateViewSlot;
52
+ };
53
+ /**
54
+ * Two independent comparisons, never one verdict.
55
+ *
56
+ * `desiredVsApplied` answers "did our write happen"; `appliedVsObserved` answers "did
57
+ * it stick". A single boolean cannot distinguish a request that was never carried out
58
+ * from one the network undid a second later, and those need opposite responses.
59
+ */
60
+ export type StateDivergence = {
61
+ readonly desiredVsApplied: SlotComparison;
62
+ readonly appliedVsObserved: SlotComparison;
63
+ };
64
+ export declare function describeStateDivergence<T>(view: ModemStateView<T, T, T>, equals: (left: T, right: T) => boolean): StateDivergence;
@@ -0,0 +1,52 @@
1
+ // Desired, applied and observed are THREE things, and this module refuses to make
2
+ // them one.
3
+ //
4
+ // The pattern is NetworkManager's: a connection PROFILE is what an operator asked
5
+ // for, an active connection's BEARER is what was actually put into force, and the
6
+ // device's own reported state is what the hardware is currently doing. All three are
7
+ // routinely different at once — a profile edited but not re-activated, a bearer that
8
+ // survived a profile change, a device that dropped registration without anything
9
+ // having been re-applied — and a merged "current state" blob has to pick one of them
10
+ // and silently lose the other two.
11
+ //
12
+ // Concretely, collapsing them makes these questions unanswerable:
13
+ // · did the operator's last change actually take effect, or is it only pending?
14
+ // · is what the device reports the consequence of our write, or of the network?
15
+ // · when a rollback is needed, what exactly do we roll back TO?
16
+ //
17
+ // So the three live in separate slots with separate `kind` discriminants, and the
18
+ // comparison below reports TWO independent divergences instead of one verdict.
19
+ // `NetworkManagerAdapter` (a later change) consumes exactly this shape.
20
+ import { viewEnvelope } from './envelope.js';
21
+ export function desiredProfile(profile, requestedAt, requestedBy) {
22
+ return { kind: 'desired', profile, requestedAt, requestedBy };
23
+ }
24
+ export function appliedConfiguration(input) {
25
+ return { kind: 'applied', ...input };
26
+ }
27
+ export function observedState(observation) {
28
+ return { kind: 'observed', observation };
29
+ }
30
+ export const STATE_VIEW_SLOTS = ['desired', 'applied', 'observed'];
31
+ export function describeStateDivergence(view, equals) {
32
+ return {
33
+ desiredVsApplied: compareSlots(view.desired === null ? undefined : view.desired.profile, view.applied === null ? undefined : view.applied.configuration, view.desired === null ? 'desired' : 'applied', equals),
34
+ appliedVsObserved: compareSlots(view.applied === null ? undefined : view.applied.configuration, observedValue(view.observed), view.applied === null ? 'applied' : 'observed', equals),
35
+ };
36
+ }
37
+ /**
38
+ * The observed value, or `undefined` when the observation carries none.
39
+ *
40
+ * An unavailable observation is `indeterminate` against anything, never `aligned`:
41
+ * "we could not read it" is not evidence that it matches.
42
+ */
43
+ function observedValue(observed) {
44
+ const view = viewEnvelope(observed.observation);
45
+ return view.kind === 'unavailable' ? undefined : view.value;
46
+ }
47
+ function compareSlots(left, right, missing, equals) {
48
+ if (left === undefined || right === undefined) {
49
+ return { status: 'indeterminate', missing };
50
+ }
51
+ return equals(left, right) ? { status: 'aligned' } : { status: 'diverged' };
52
+ }
@@ -0,0 +1,2 @@
1
+ export declare const MODEM_OPERATION_IDS: readonly ["modemmanager.radio-modes", "modemmanager.mode-combination", "modemmanager.bands", "modemmanager.signal", "modemmanager.sim", "modemmanager.power", "modemmanager.usb-composition", "status", "signal", "mode", "data", "ufi.signal.read", "ufi.details.read", "nv.write", "efs.write", "identity.write", "calibration.write", "firmware.flash", "edl.automation", "driver.blind-retry", "interface.blind-retry", "diag.write", "diag.info-probe", "shell.transport-fallback"];
2
+ export type ModemOperationId = (typeof MODEM_OPERATION_IDS)[number];
@@ -0,0 +1,26 @@
1
+ export const MODEM_OPERATION_IDS = Object.freeze([
2
+ 'modemmanager.radio-modes',
3
+ 'modemmanager.mode-combination',
4
+ 'modemmanager.bands',
5
+ 'modemmanager.signal',
6
+ 'modemmanager.sim',
7
+ 'modemmanager.power',
8
+ 'modemmanager.usb-composition',
9
+ 'status',
10
+ 'signal',
11
+ 'mode',
12
+ 'data',
13
+ 'ufi.signal.read',
14
+ 'ufi.details.read',
15
+ 'nv.write',
16
+ 'efs.write',
17
+ 'identity.write',
18
+ 'calibration.write',
19
+ 'firmware.flash',
20
+ 'edl.automation',
21
+ 'driver.blind-retry',
22
+ 'interface.blind-retry',
23
+ 'diag.write',
24
+ 'diag.info-probe',
25
+ 'shell.transport-fallback',
26
+ ]);
@@ -0,0 +1,72 @@
1
+ import type { DeviceGeneration, OperationCompletion, OperationDescriptor, OperationResult, PhysicalModemId } from '../domain/index.js';
2
+ export type OperationPreconditionRequest = {
3
+ readonly operationId: string;
4
+ readonly physicalModemId: PhysicalModemId;
5
+ readonly generation: DeviceGeneration;
6
+ readonly descriptorId: string;
7
+ readonly preconditions: readonly string[];
8
+ };
9
+ export type OperationPreconditionResult = {
10
+ readonly status: 'satisfied';
11
+ } | {
12
+ readonly status: 'refused';
13
+ readonly reason: string;
14
+ };
15
+ /** Live operation facts. Implementations must inspect them for every invocation. */
16
+ export interface OperationPreconditionPort {
17
+ check(request: OperationPreconditionRequest): Promise<OperationPreconditionResult>;
18
+ }
19
+ export type OperationAttemptContext = {
20
+ readonly operationId: string;
21
+ readonly generation: DeviceGeneration;
22
+ readonly attempt: number;
23
+ };
24
+ export type OperationJournalEvent<I, O> = {
25
+ readonly phase: 'started';
26
+ readonly operationId: string;
27
+ readonly physicalModemId: PhysicalModemId;
28
+ readonly generation: DeviceGeneration;
29
+ readonly descriptor: OperationDescriptor<I, O>;
30
+ readonly input: I;
31
+ } | {
32
+ readonly phase: 'completed';
33
+ readonly operationId: string;
34
+ readonly physicalModemId: PhysicalModemId;
35
+ readonly generation: DeviceGeneration;
36
+ readonly descriptor: OperationDescriptor<I, O>;
37
+ readonly result: OperationResult<O>;
38
+ };
39
+ export interface OperationJournalHook<I, O> {
40
+ record(event: OperationJournalEvent<I, O>): Promise<void>;
41
+ }
42
+ export type OperationExecution<I, O> = {
43
+ readonly operationId: string;
44
+ readonly physicalModemId: PhysicalModemId;
45
+ readonly descriptor: OperationDescriptor<I, O>;
46
+ readonly input: I;
47
+ readonly execute: (context: OperationAttemptContext) => Promise<OperationCompletion<O>>;
48
+ readonly readback?: (context: OperationAttemptContext) => Promise<OperationCompletion<O>>;
49
+ readonly rollback?: (context: OperationAttemptContext) => Promise<OperationCompletion<void>>;
50
+ readonly journal?: OperationJournalHook<I, O>;
51
+ };
52
+ export type ReconciliationExecution = {
53
+ readonly physicalModemId: PhysicalModemId;
54
+ readonly generation: DeviceGeneration;
55
+ readonly run: () => Promise<{
56
+ readonly status: 'reconciled';
57
+ } | {
58
+ readonly status: 'failed';
59
+ readonly reason: string;
60
+ }>;
61
+ };
62
+ export type ReconciliationResult = {
63
+ readonly status: 'reconciled';
64
+ readonly generation: DeviceGeneration;
65
+ } | {
66
+ readonly status: 'not-required';
67
+ readonly generation: DeviceGeneration;
68
+ } | {
69
+ readonly status: 'failed';
70
+ readonly reason: 'stale-generation' | string;
71
+ readonly generation: DeviceGeneration;
72
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export * from './operation-engine.js';
@@ -0,0 +1 @@
1
+ export * from './operation-engine.js';
@@ -0,0 +1,16 @@
1
+ import { type DeviceGeneration, type OperationResult, type PhysicalModemId } from '../domain/index.js';
2
+ import type { ModemControlCompositionRoot } from '../safety/index.js';
3
+ import type { OperationExecution, OperationPreconditionPort, ReconciliationExecution, ReconciliationResult } from './contracts.js';
4
+ export * from './contracts.js';
5
+ export type OperationEngineOptions = {
6
+ readonly root: ModemControlCompositionRoot;
7
+ readonly currentGeneration: (physicalModemId: PhysicalModemId) => DeviceGeneration;
8
+ readonly preconditions: OperationPreconditionPort;
9
+ };
10
+ export declare class OperationEngine {
11
+ #private;
12
+ constructor(options: OperationEngineOptions);
13
+ invoke<I, O>(execution: OperationExecution<I, O>): Promise<OperationResult<O>>;
14
+ reconcile(execution: ReconciliationExecution): Promise<ReconciliationResult>;
15
+ }
16
+ export declare function createOperationEngine(options: OperationEngineOptions): OperationEngine;