@ceralive/modem-control 0.2.0 → 1.1.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 (464) hide show
  1. package/README.md +317 -0
  2. package/dist/backend/at-lease.d.ts +57 -0
  3. package/dist/backend/at-lease.js +109 -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 +76 -0
  61. package/dist/backend/transition-preconditions.js +64 -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 +196 -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 +19 -0
  146. package/dist/index.js +26 -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 +47 -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/operations/contracts.d.ts +72 -0
  196. package/dist/operations/contracts.js +1 -0
  197. package/dist/operations/index.d.ts +1 -0
  198. package/dist/operations/index.js +1 -0
  199. package/dist/operations/operation-engine.d.ts +16 -0
  200. package/dist/operations/operation-engine.js +194 -0
  201. package/dist/ports/index.d.ts +12 -0
  202. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  203. package/dist/ports/location.d.ts +87 -0
  204. package/dist/ports/location.js +36 -0
  205. package/dist/ports/modem-manager.d.ts +89 -0
  206. package/dist/ports/modem-manager.js +9 -0
  207. package/dist/ports/mutation-admission.d.ts +27 -0
  208. package/dist/ports/mutation-admission.js +9 -0
  209. package/dist/ports/network-manager.d.ts +68 -0
  210. package/dist/ports/network-manager.js +13 -0
  211. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  212. package/dist/ports/observation.js +7 -0
  213. package/dist/ports/ops.d.ts +44 -0
  214. package/dist/ports/ops.js +16 -0
  215. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  216. package/dist/ports/receipts.js +9 -0
  217. package/dist/ports/reconcile.d.ts +33 -0
  218. package/dist/ports/reconcile.js +200 -0
  219. package/dist/ports/resource-ownership.d.ts +29 -0
  220. package/dist/ports/resource-ownership.js +1 -0
  221. package/dist/ports/router.d.ts +19 -0
  222. package/dist/ports/router.js +7 -0
  223. package/dist/ports/sms.d.ts +64 -0
  224. package/dist/ports/sms.js +24 -0
  225. package/dist/ports/uhubctl.d.ts +6 -0
  226. package/dist/ports/uhubctl.js +1 -0
  227. package/dist/providers/contracts.d.ts +124 -0
  228. package/dist/providers/contracts.js +10 -0
  229. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  230. package/dist/providers/huawei-hilink/index.js +2 -0
  231. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  232. package/dist/providers/huawei-hilink/operations.js +56 -0
  233. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  234. package/dist/providers/huawei-hilink/provider.js +76 -0
  235. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  236. package/dist/providers/huawei-hilink/runtime.js +171 -0
  237. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  238. package/dist/providers/huawei-hilink/session.js +120 -0
  239. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  240. package/dist/providers/huawei-hilink/transport.js +1 -0
  241. package/dist/providers/index.d.ts +8 -0
  242. package/dist/providers/index.js +8 -0
  243. package/dist/providers/matcher.d.ts +3 -0
  244. package/dist/providers/matcher.js +205 -0
  245. package/dist/providers/modem-manager/errors.d.ts +7 -0
  246. package/dist/providers/modem-manager/errors.js +37 -0
  247. package/dist/providers/modem-manager/generic-operations.d.ts +8 -0
  248. package/dist/providers/modem-manager/generic-operations.js +207 -0
  249. package/dist/providers/modem-manager/index.d.ts +3 -0
  250. package/dist/providers/modem-manager/index.js +3 -0
  251. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  252. package/dist/providers/modem-manager/module-operations.js +118 -0
  253. package/dist/providers/modem-manager/provider.d.ts +39 -0
  254. package/dist/providers/modem-manager/provider.js +152 -0
  255. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  256. package/dist/providers/modem-manager/snapshot.js +204 -0
  257. package/dist/providers/modem-manager/types.d.ts +135 -0
  258. package/dist/providers/modem-manager/types.js +1 -0
  259. package/dist/providers/network-manager/adapter.d.ts +71 -0
  260. package/dist/providers/network-manager/adapter.js +348 -0
  261. package/dist/providers/network-manager/index.d.ts +2 -0
  262. package/dist/providers/network-manager/index.js +2 -0
  263. package/dist/providers/network-manager/types.d.ts +163 -0
  264. package/dist/providers/network-manager/types.js +77 -0
  265. package/dist/providers/registry.d.ts +13 -0
  266. package/dist/providers/registry.js +33 -0
  267. package/dist/providers/ufi-himi/index.d.ts +6 -0
  268. package/dist/providers/ufi-himi/index.js +6 -0
  269. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  270. package/dist/providers/ufi-himi/operations.js +66 -0
  271. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  272. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  273. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  274. package/dist/providers/ufi-himi/provider.js +204 -0
  275. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  276. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  277. package/dist/providers/ufi-himi/session.d.ts +46 -0
  278. package/dist/providers/ufi-himi/session.js +92 -0
  279. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  280. package/dist/providers/ufi-himi/transport.js +25 -0
  281. package/dist/providers/zte-goform/index.d.ts +2 -0
  282. package/dist/providers/zte-goform/index.js +2 -0
  283. package/dist/providers/zte-goform/provider.d.ts +51 -0
  284. package/dist/providers/zte-goform/provider.js +101 -0
  285. package/dist/providers/zte-goform/session.d.ts +17 -0
  286. package/dist/providers/zte-goform/session.js +133 -0
  287. package/dist/providers/zte-goform/transport.d.ts +16 -0
  288. package/dist/providers/zte-goform/transport.js +1 -0
  289. package/dist/radio/band-truth.d.ts +50 -0
  290. package/dist/radio/band-truth.js +92 -0
  291. package/dist/radio/index.d.ts +3 -0
  292. package/dist/radio/index.js +10 -0
  293. package/dist/radio/mode-combinations.d.ts +78 -0
  294. package/dist/radio/mode-combinations.js +198 -0
  295. package/dist/radio/mode-truth.d.ts +67 -0
  296. package/dist/radio/mode-truth.js +112 -0
  297. package/dist/redact.d.ts +15 -0
  298. package/dist/redact.js +189 -0
  299. package/dist/safety/composition-root.d.ts +28 -0
  300. package/dist/safety/composition-root.js +65 -0
  301. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  302. package/dist/safety/flock-resource-ownership.js +151 -0
  303. package/dist/safety/index.d.ts +2 -0
  304. package/dist/safety/index.js +2 -0
  305. package/dist/sms/dbus-messaging.d.ts +17 -0
  306. package/dist/sms/dbus-messaging.js +185 -0
  307. package/dist/sms/inbox-store.d.ts +10 -0
  308. package/dist/sms/inbox-store.js +82 -0
  309. package/dist/sms/index.d.ts +4 -0
  310. package/dist/sms/index.js +10 -0
  311. package/dist/sms/mmcli-parse.d.ts +54 -0
  312. package/dist/sms/mmcli-parse.js +224 -0
  313. package/dist/sms/normalize.d.ts +42 -0
  314. package/dist/sms/normalize.js +95 -0
  315. package/dist/testing/domain-fakes.d.ts +58 -0
  316. package/dist/testing/domain-fakes.js +98 -0
  317. package/dist/testing/index.d.ts +2 -0
  318. package/dist/testing/index.js +17 -0
  319. package/dist/testing/provider-fakes.d.ts +45 -0
  320. package/dist/testing/provider-fakes.js +64 -0
  321. package/dist/transport/calls.d.ts +9 -0
  322. package/dist/transport/calls.js +88 -0
  323. package/dist/transport/codec.d.ts +3 -0
  324. package/dist/transport/codec.js +207 -0
  325. package/dist/transport/dbus-native.d.ts +57 -0
  326. package/dist/transport/dbus-native.js +17 -0
  327. package/dist/transport/errors.d.ts +21 -0
  328. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  329. package/dist/transport/index.d.ts +4 -0
  330. package/dist/transport/index.js +9 -0
  331. package/dist/transport/signals.d.ts +15 -0
  332. package/dist/transport/signals.js +123 -0
  333. package/dist/transport/signature.d.ts +7 -0
  334. package/dist/transport/signature.js +94 -0
  335. package/dist/transport/transport.d.ts +2 -0
  336. package/dist/transport/transport.js +202 -0
  337. package/dist/transport/types.d.ts +61 -0
  338. package/dist/transport/types.js +19 -0
  339. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  340. package/dist/usb-mode/catalog-schema.js +97 -0
  341. package/dist/usb-mode/catalog.d.ts +21 -0
  342. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  343. package/dist/usb-mode/certified-catalog.json +67 -0
  344. package/dist/usb-mode/index.d.ts +5 -0
  345. package/dist/usb-mode/index.js +15 -0
  346. package/dist/usb-mode/ingestion.d.ts +111 -0
  347. package/dist/usb-mode/ingestion.js +187 -0
  348. package/dist/usb-mode/promotion-review.d.ts +21 -0
  349. package/dist/usb-mode/promotion-review.js +87 -0
  350. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  351. package/dist/usb-mode/usb-devices-parse.js +157 -0
  352. package/dist/ussd/calls.d.ts +32 -0
  353. package/dist/ussd/calls.js +96 -0
  354. package/dist/ussd/index.d.ts +5 -0
  355. package/dist/ussd/index.js +12 -0
  356. package/dist/ussd/mm-ussd.d.ts +37 -0
  357. package/dist/ussd/mm-ussd.js +205 -0
  358. package/dist/ussd/refusal.d.ts +53 -0
  359. package/dist/ussd/refusal.js +154 -0
  360. package/dist/ussd/registration.d.ts +20 -0
  361. package/dist/ussd/registration.js +101 -0
  362. package/dist/ussd/session.d.ts +84 -0
  363. package/dist/ussd/session.js +163 -0
  364. package/package.json +38 -4
  365. package/src/backend/at-lease.test.ts +0 -106
  366. package/src/backend/at-lease.ts +0 -158
  367. package/src/backend/cell-info.test.ts +0 -154
  368. package/src/backend/cell-info.ts +0 -160
  369. package/src/backend/device-classifier.test.ts +0 -168
  370. package/src/backend/device-classifier.ts +0 -248
  371. package/src/backend/enrichment.ts +0 -96
  372. package/src/backend/features.test.ts +0 -162
  373. package/src/backend/features.ts +0 -179
  374. package/src/backend/identity-ladder.test.ts +0 -117
  375. package/src/backend/identity-ladder.ts +0 -221
  376. package/src/backend/identity-registry.test.ts +0 -89
  377. package/src/backend/identity-registry.ts +0 -151
  378. package/src/backend/index.ts +0 -221
  379. package/src/backend/lifecycle-interlock.ts +0 -38
  380. package/src/backend/managed-objects.ts +0 -108
  381. package/src/backend/mapping.ts +0 -160
  382. package/src/backend/mm-backend.ts +0 -191
  383. package/src/backend/mm-mutations.ts +0 -228
  384. package/src/backend/modem-actor.test.ts +0 -95
  385. package/src/backend/modem-actor.ts +0 -112
  386. package/src/backend/nm-auto-apn.ts +0 -161
  387. package/src/backend/nm-gsm-fields.ts +0 -122
  388. package/src/backend/nmcli-nm-port.ts +0 -228
  389. package/src/backend/nmcli-runner.ts +0 -52
  390. package/src/backend/observer.ts +0 -297
  391. package/src/backend/power-contract.test.ts +0 -40
  392. package/src/backend/power-contract.ts +0 -83
  393. package/src/backend/recovery-attribution.test.ts +0 -102
  394. package/src/backend/recovery-attribution.ts +0 -86
  395. package/src/backend/recovery-budget.test.ts +0 -64
  396. package/src/backend/recovery-budget.ts +0 -84
  397. package/src/backend/recovery-ladder.test.ts +0 -257
  398. package/src/backend/recovery-ladder.ts +0 -249
  399. package/src/backend/router-ethernet.test.ts +0 -71
  400. package/src/backend/router-ethernet.ts +0 -90
  401. package/src/backend/row-store.ts +0 -105
  402. package/src/backend/signal-setup.ts +0 -112
  403. package/src/backend/sim-unlock.ts +0 -193
  404. package/src/backend/transition-preconditions.ts +0 -149
  405. package/src/backend/usage/accounting.test.ts +0 -147
  406. package/src/backend/usage/accounting.ts +0 -123
  407. package/src/backend/usage/billing-cycle.test.ts +0 -62
  408. package/src/backend/usage/billing-cycle.ts +0 -45
  409. package/src/backend/usage/index.ts +0 -37
  410. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  411. package/src/backend/usage/sampler.test.ts +0 -219
  412. package/src/backend/usage/sampler.ts +0 -228
  413. package/src/backend/usage/store.test.ts +0 -148
  414. package/src/backend/usage/store.ts +0 -177
  415. package/src/backend/usb-enumerator.test.ts +0 -87
  416. package/src/backend/usb-enumerator.ts +0 -181
  417. package/src/backend/usb-mode-transition.test.ts +0 -323
  418. package/src/backend/usb-mode-transition.ts +0 -253
  419. package/src/domain/brand.ts +0 -29
  420. package/src/domain/errors.ts +0 -77
  421. package/src/domain/guards.test.ts +0 -218
  422. package/src/domain/guards.ts +0 -144
  423. package/src/domain/identity.test.ts +0 -83
  424. package/src/domain/identity.ts +0 -165
  425. package/src/domain/index.ts +0 -12
  426. package/src/domain/snapshot.test.ts +0 -266
  427. package/src/domain/snapshot.ts +0 -120
  428. package/src/index.test.ts +0 -6
  429. package/src/index.ts +0 -15
  430. package/src/ports/README.md +0 -61
  431. package/src/ports/forbidden-surface.test.ts +0 -241
  432. package/src/ports/modem-manager.ts +0 -72
  433. package/src/ports/network-manager.ts +0 -87
  434. package/src/ports/ops.ts +0 -60
  435. package/src/ports/ops.type-test.ts +0 -39
  436. package/src/ports/receipts.test.ts +0 -153
  437. package/src/ports/reconcile.test.ts +0 -152
  438. package/src/ports/reconcile.ts +0 -338
  439. package/src/ports/router.ts +0 -29
  440. package/src/redact.test.ts +0 -82
  441. package/src/redact.ts +0 -73
  442. package/src/transport/README.md +0 -65
  443. package/src/transport/calls.ts +0 -113
  444. package/src/transport/characterization.test.ts +0 -260
  445. package/src/transport/codec.test.ts +0 -118
  446. package/src/transport/codec.ts +0 -240
  447. package/src/transport/conformance-python.test.ts +0 -152
  448. package/src/transport/conformance-same-lib.test.ts +0 -115
  449. package/src/transport/dbus-native-lib.d.ts +0 -19
  450. package/src/transport/dbus-native.ts +0 -85
  451. package/src/transport/index.ts +0 -30
  452. package/src/transport/no-library-leak.test.ts +0 -61
  453. package/src/transport/reliability.test.ts +0 -173
  454. package/src/transport/signals.ts +0 -150
  455. package/src/transport/signature.ts +0 -110
  456. package/src/transport/test-support/fake-service.ts +0 -168
  457. package/src/transport/test-support/independent-producer.py +0 -110
  458. package/src/transport/test-support/private-bus.ts +0 -66
  459. package/src/transport/transport.ts +0 -250
  460. package/src/transport/types.ts +0 -118
  461. package/src/usb-mode/catalog-schema.test.ts +0 -181
  462. package/src/usb-mode/catalog-schema.ts +0 -113
  463. package/src/usb-mode/certified-catalog.json +0 -67
  464. package/src/usb-mode/index.ts +0 -27
@@ -1,151 +0,0 @@
1
- // The identity registry — ONE logical row per physical slot, across replugs.
2
- //
3
- // The epoch observer (A3.1) keys rows by the MM object path, which CHANGES on
4
- // replug and daemon restart. This registry sits above it and keys rows by the
5
- // STABLE identifier the ladder resolves (slot-UID / Physdev / sysfs / unique
6
- // equipment id), so a modem that disconnects and reconnects to the SAME slot
7
- // resolves to the SAME logical row instead of a duplicate.
8
- //
9
- // It also names the transitions the ladder can observe:
10
- //
11
- // - `attached` — a stable key we have not seen before.
12
- // - `replugged` — same stable key, same equipment: one row, new path.
13
- // - `equipment-swapped-in-slot` — same slot, DIFFERENT equipment. The slot keeps
14
- // its policy (slot-inherits-policy): unplug modem A,
15
- // plug modem B into the same slot, B adopts A's
16
- // slot-bound policy.
17
- // - `equipment-moved` — same equipment, DIFFERENT slot: the modem was
18
- // physically moved to another port.
19
-
20
- import type { EquipmentId, LogicalSlotId, RuntimePath } from '../domain';
21
- import type { ResolvedIdentity } from './identity-ladder';
22
-
23
- /** One durable logical row, keyed by the ladder's stable identifier. */
24
- export interface IdentityRow {
25
- /** The stable durable key (`slot:…` / `physdev:…` / `sysfs:…` / `equip:…`). */
26
- readonly stableKey: string;
27
- /** The resolved slot, when the row was slot-resolved (rungs 1-3). */
28
- readonly logicalSlotId?: LogicalSlotId;
29
- /** The equipment currently occupying this slot. */
30
- readonly equipmentId: EquipmentId;
31
- /** The live MM path — updated on every replug (never a durable key). */
32
- readonly runtimePath: RuntimePath;
33
- }
34
-
35
- /** A transition the registry detected while applying a resolved identity. */
36
- export type IdentityTransition =
37
- | { readonly kind: 'attached'; readonly row: IdentityRow }
38
- | { readonly kind: 'replugged'; readonly row: IdentityRow; readonly previousPath: RuntimePath }
39
- | {
40
- readonly kind: 'equipment-swapped-in-slot';
41
- readonly row: IdentityRow;
42
- readonly previousEquipment: EquipmentId;
43
- }
44
- | {
45
- readonly kind: 'equipment-moved';
46
- readonly row: IdentityRow;
47
- readonly previousKey: string;
48
- readonly previousSlot?: LogicalSlotId;
49
- };
50
-
51
- const equipmentValue = (equipment: EquipmentId): string | undefined =>
52
- equipment.provenance !== 'none' && equipment.value.trim().length > 0
53
- ? equipment.value
54
- : undefined;
55
-
56
- /**
57
- * Tracks logical modem rows across replug/swap/move. Stateful by design — it holds
58
- * the last-known row per stable key. `apply()` folds one resolved identity in and
59
- * reports the transition it produced.
60
- */
61
- export class IdentityRegistry {
62
- readonly #rows = new Map<string, IdentityRow>();
63
-
64
- /** A snapshot of the current logical rows, in insertion order. */
65
- get rows(): IdentityRow[] {
66
- return [...this.#rows.values()];
67
- }
68
-
69
- /** The row for a stable key, or `undefined`. */
70
- get(stableKey: string): IdentityRow | undefined {
71
- return this.#rows.get(stableKey);
72
- }
73
-
74
- /** Drop a row (e.g. after a current-epoch removal). */
75
- remove(stableKey: string): void {
76
- this.#rows.delete(stableKey);
77
- }
78
-
79
- /**
80
- * Fold one resolved identity into the registry and report the transition.
81
- * Keeps ONE row per stable key: a replug into the same slot updates the live
82
- * path in place rather than adding a duplicate.
83
- */
84
- apply(resolved: ResolvedIdentity): IdentityTransition {
85
- const row = this.#rowFrom(resolved);
86
- const existing = this.#rows.get(row.stableKey);
87
-
88
- if (existing !== undefined) {
89
- return this.#applyToExisting(existing, resolved, row);
90
- }
91
-
92
- // A unique equipment id at a NEW stable key that already lives elsewhere
93
- // means the modem physically moved to a different slot/port.
94
- const moved = this.#findByEquipment(row.equipmentId, row.stableKey);
95
- if (moved !== undefined) {
96
- this.#rows.delete(moved.stableKey);
97
- this.#rows.set(row.stableKey, row);
98
- return {
99
- kind: 'equipment-moved',
100
- row,
101
- previousKey: moved.stableKey,
102
- ...(moved.logicalSlotId !== undefined ? { previousSlot: moved.logicalSlotId } : {}),
103
- };
104
- }
105
-
106
- this.#rows.set(row.stableKey, row);
107
- return { kind: 'attached', row };
108
- }
109
-
110
- #applyToExisting(
111
- existing: IdentityRow,
112
- resolved: ResolvedIdentity,
113
- row: IdentityRow,
114
- ): IdentityTransition {
115
- const before = equipmentValue(existing.equipmentId);
116
- const after = equipmentValue(resolved.identity.equipmentId);
117
-
118
- if (before !== undefined && after !== undefined && before !== after) {
119
- // Same slot, different equipment — the slot keeps its policy binding.
120
- this.#rows.set(row.stableKey, row);
121
- return { kind: 'equipment-swapped-in-slot', row, previousEquipment: existing.equipmentId };
122
- }
123
-
124
- // Same slot, same (or unchanged) equipment — a replug: one row, new path.
125
- this.#rows.set(row.stableKey, row);
126
- return { kind: 'replugged', row, previousPath: existing.runtimePath };
127
- }
128
-
129
- #rowFrom(resolved: ResolvedIdentity): IdentityRow {
130
- const { identity, stableKey } = resolved;
131
- return {
132
- stableKey,
133
- equipmentId: identity.equipmentId,
134
- runtimePath: identity.runtimePath,
135
- ...(identity.logicalSlotId !== undefined ? { logicalSlotId: identity.logicalSlotId } : {}),
136
- };
137
- }
138
-
139
- #findByEquipment(equipment: EquipmentId, exceptKey: string): IdentityRow | undefined {
140
- const value = equipmentValue(equipment);
141
- if (value === undefined) {
142
- return undefined;
143
- }
144
- for (const row of this.#rows.values()) {
145
- if (row.stableKey !== exceptKey && equipmentValue(row.equipmentId) === value) {
146
- return row;
147
- }
148
- }
149
- return undefined;
150
- }
151
- }
@@ -1,221 +0,0 @@
1
- // Backend adapters — the concrete D-Bus implementations of the port contracts.
2
- //
3
- // A3.1 lands the epoch-scoped `MmDbusObserver` (the read side). A3.2 adds MM
4
- // feature detection + the stable identity ladder. Later A3 waves add mutations +
5
- // Signal.Setup (A3.3) and the recovery ladder (A3.4) here.
6
-
7
- export {
8
- AT_BASELINE_ALLOWLIST,
9
- type AtAuditEntry,
10
- type AtAuditSink,
11
- AtCommandLease,
12
- type AtCommandLeaseDeps,
13
- AtCommandNotAllowedError,
14
- type AtCommandSender,
15
- AtCommandTimeoutError,
16
- type AtResponse,
17
- computeAtAllowlist,
18
- } from './at-lease';
19
- export {
20
- type CellInfoProvenance,
21
- type CellReading,
22
- compareServing,
23
- normalizeCellInfo,
24
- normalizeCellReading,
25
- selectServingCell,
26
- } from './cell-info';
27
- export {
28
- MM_BUS_NAME,
29
- MM_MANAGER_IFACE,
30
- MM_ROOT_PATH,
31
- MODEM_IFACE,
32
- MODEM3GPP_IFACE,
33
- SIM_IFACE,
34
- } from './constants';
35
- export {
36
- classifyDevice,
37
- type DeviceClass,
38
- type DeviceClassification,
39
- descriptorsMatch,
40
- detectUsbMode,
41
- type UsbDeviceSnapshot,
42
- type UsbInterface,
43
- } from './device-classifier';
44
- export {
45
- buildEnrichment,
46
- type EsimInfo,
47
- type EsimStatus,
48
- type ModemEnrichment,
49
- readEsimInfo,
50
- readRevision,
51
- type SimType,
52
- } from './enrichment';
53
- export {
54
- detectMmFeatures,
55
- detectModemFeatures,
56
- type MmFeatures,
57
- type MmPropertyProbe,
58
- type MmVersion,
59
- parseMmVersion,
60
- probeModemProperties,
61
- } from './features';
62
- export {
63
- looksLikeSlotUid,
64
- type ModemIdentityFacts,
65
- modemIdentityFactsFromTree,
66
- type ResolvedIdentity,
67
- resolveModemIdentities,
68
- resolveModemIdentity,
69
- SLOT_UID_PREFIX,
70
- type SlotSource,
71
- } from './identity-ladder';
72
- export {
73
- IdentityRegistry,
74
- type IdentityRow,
75
- type IdentityTransition,
76
- } from './identity-registry';
77
- export {
78
- ALLOW_ALL_INTERLOCK,
79
- type InterlockDecision,
80
- type InterlockTarget,
81
- type LifecycleInterlock,
82
- } from './lifecycle-interlock';
83
- export {
84
- asManagedObjects,
85
- type DecodedInterfaces,
86
- type DecodedManagedObjects,
87
- type DecodedObject,
88
- type DecodedProps,
89
- fetchManagedObjects,
90
- findInterface,
91
- findObject,
92
- followObjectPath,
93
- hasInterface,
94
- numberProp,
95
- objectPaths,
96
- pathsWithInterface,
97
- propValue,
98
- stringProp,
99
- } from './managed-objects';
100
- export {
101
- createMmDbusBackend,
102
- MmDbusBackend,
103
- type MmDbusBackendOptions,
104
- } from './mm-backend';
105
- export { MmMutations, type MmMutationsDeps } from './mm-mutations';
106
- export {
107
- ModemActor,
108
- NO_OP_QUIESCE,
109
- type QuiesceHook,
110
- type QuiesceLeaseHandle,
111
- type QuiesceTarget,
112
- } from './modem-actor';
113
- export {
114
- AUTO_APN_ADVISORY,
115
- type AutoApnAdvisory,
116
- type AutoApnTransitionResult,
117
- autoApnCapableFromVersion,
118
- autoApnSupportedByVersion,
119
- classifyActivation,
120
- type ManualApn,
121
- parseNmVersion,
122
- probeAutoApnCapability,
123
- toAutoArgs,
124
- toManualArgs,
125
- } from './nm-auto-apn';
126
- export {
127
- buildProfile,
128
- cliArg,
129
- createGsmArgs,
130
- flattenPairs,
131
- gsmFieldPairs,
132
- passwordFlags,
133
- patchPairs,
134
- } from './nm-gsm-fields';
135
- export {
136
- NmcliNmPort,
137
- type NmcliNmPortOptions,
138
- } from './nmcli-nm-port';
139
- export {
140
- type NmcliResult,
141
- type NmcliRunner,
142
- parseTerse,
143
- runNmcli,
144
- SpawnNmcliRunner,
145
- } from './nmcli-runner';
146
- export {
147
- createMmDbusObserver,
148
- type EpochRefreshEvent,
149
- MmDbusObserver,
150
- type MmDbusObserverOptions,
151
- } from './observer';
152
- export {
153
- NONE_POWER_CAPABILITY,
154
- NONE_POWER_HOOK,
155
- type PowerCapability,
156
- type PowerCapabilityKind,
157
- type PowerCycleContext,
158
- type PowerCycleResult,
159
- type PowerHook,
160
- type PreferredUsbMode,
161
- unsupportedPowerHook,
162
- } from './power-contract';
163
- export {
164
- attributeFault,
165
- attributeSnapshot,
166
- type FaultAttribution,
167
- type FaultSymptoms,
168
- symptomsFromSnapshot,
169
- } from './recovery-attribution';
170
- export {
171
- type BudgetDecision,
172
- beginAttempt,
173
- DEFAULT_RECOVERY_BUDGET,
174
- INITIAL_BUDGET_STATE,
175
- markRecovered,
176
- type RecoveryBudget,
177
- type RecoveryBudgetState,
178
- } from './recovery-budget';
179
- export {
180
- DEFAULT_LADDER_CONFIG,
181
- LADDER_ORDER,
182
- RecoveryLadder,
183
- type RecoveryLadderConfig,
184
- type RecoveryLadderDeps,
185
- type RecoveryOutcome,
186
- type RecoveryOutcomeKind,
187
- type RecoveryRequest,
188
- type RecoveryRung,
189
- type RecoveryStepContext,
190
- type RecoveryStepGate,
191
- type RecoveryStepReport,
192
- type RecoverySteps,
193
- type StepOutcome,
194
- } from './recovery-ladder';
195
- export { createRouterEthernetProbe, type RouterEthernetProbeDeps } from './router-ethernet';
196
- export {
197
- DEFAULT_SIGNAL_INTERVAL_SECONDS,
198
- type SignalCadence,
199
- SignalSetupManager,
200
- type SignalSetupManagerOptions,
201
- } from './signal-setup';
202
- export { sendSimPin, sendSimPuk } from './sim-unlock';
203
- export {
204
- ALLOW_ALL_TRANSITION_INTERLOCK,
205
- checkTransitionPreconditions,
206
- type InterlockHold,
207
- type PreconditionResult,
208
- type TransitionInterlock,
209
- type TransitionReadiness,
210
- type UsbModeTransitionOutcome,
211
- type UsbModeTransitionRequest,
212
- } from './transition-preconditions';
213
- export * from './usage';
214
- export {
215
- createUsbEnumerator,
216
- enumerateUsbDevices,
217
- parseUdevDatabase,
218
- type UsbEnumerator,
219
- type UsbEnumeratorDeps,
220
- } from './usb-enumerator';
221
- export { UsbModeTransition, type UsbModeTransitionDeps } from './usb-mode-transition';
@@ -1,38 +0,0 @@
1
- // The pluggable safety interlock the recovery ladder consults before disruption.
2
- //
3
- // A disruptive recovery step (deactivate NM, disable MM, Reset(), power-cycle) must
4
- // never fire while the modem is carrying a live stream. The ladder therefore asks a
5
- // `LifecycleInterlock` BEFORE every disruptive step. Phase A (CLI) injects the
6
- // always-allow stub below; Phase B wires CeraUI's real streaming-admission check
7
- // into this SAME interface — the ladder code does not change, only the injected
8
- // instance. A4.2's USB-mode transition reuses this exact interlock shape.
9
-
10
- /** What a disruptive step is about to act on — enough for an interlock to decide. */
11
- export interface InterlockTarget {
12
- readonly stableKey: string;
13
- }
14
-
15
- /** An interlock verdict. A denial ALWAYS carries a reason (why it is unsafe now). */
16
- export type InterlockDecision =
17
- | { readonly allow: true }
18
- | { readonly allow: false; readonly reason: string };
19
-
20
- /**
21
- * The safety interlock consulted before each disruptive recovery step. Returning
22
- * `{ allow: false, reason }` stops the ladder — the modem is left as-is rather than
23
- * disrupted mid-stream.
24
- */
25
- export interface LifecycleInterlock {
26
- canDisrupt(target: InterlockTarget): Promise<InterlockDecision>;
27
- }
28
-
29
- /**
30
- * The Phase-A interlock: always allows. There is no streaming-admission signal in
31
- * the CLI, so nothing to block against. Phase B replaces this instance with a
32
- * real streaming-aware interlock; no ladder code changes.
33
- */
34
- export const ALLOW_ALL_INTERLOCK: LifecycleInterlock = {
35
- canDisrupt(): Promise<InterlockDecision> {
36
- return Promise.resolve({ allow: true });
37
- },
38
- };
@@ -1,108 +0,0 @@
1
- // Walkers over a DECODED `GetManagedObjects` / `InterfacesAdded` tree.
2
- //
3
- // The transport decodes `a{oa{sa{sv}}}` into nested tuple arrays: a dict `a{sv}`
4
- // becomes `[key, variant][]` and a variant becomes `{ signature, value }`. These
5
- // accessors navigate that structure by object path and interface name. They live in
6
- // `src` (not the A2.3 test fake's `tree.ts`) because the observer that ships must not
7
- // import test-support — the published package would not contain it.
8
-
9
- import type { DbusTransport, DbusValue, DbusVariant } from '../transport';
10
- import { MM_ROOT_PATH, OBJECT_MANAGER_IFACE } from './constants';
11
-
12
- /** One interface's property entries: `[propertyName, variant][]`. */
13
- export type DecodedProps = ReadonlyArray<readonly [string, DbusVariant]>;
14
- /** One object's interfaces: `[interfaceName, props][]`. */
15
- export type DecodedInterfaces = ReadonlyArray<readonly [string, DecodedProps]>;
16
- /** One managed object: `[objectPath, interfaces]`. */
17
- export type DecodedObject = readonly [string, DecodedInterfaces];
18
- /** The whole `a{oa{sa{sv}}}` payload. */
19
- export type DecodedManagedObjects = readonly DecodedObject[];
20
-
21
- /** Treat a `GetManagedObjects` reply body value as the decoded tree. */
22
- export function asManagedObjects(value: DbusValue | undefined): DecodedManagedObjects {
23
- if (!Array.isArray(value)) {
24
- throw new TypeError('managed-objects payload is not an array');
25
- }
26
- return value as unknown as DecodedManagedObjects;
27
- }
28
-
29
- /** Call `ObjectManager.GetManagedObjects` on `destination` and decode the reply. */
30
- export async function fetchManagedObjects(
31
- transport: DbusTransport,
32
- destination: string,
33
- ): Promise<DecodedManagedObjects> {
34
- const reply = await transport.callMethod({
35
- destination,
36
- path: MM_ROOT_PATH,
37
- interface: OBJECT_MANAGER_IFACE,
38
- member: 'GetManagedObjects',
39
- });
40
- return asManagedObjects(reply.body[0]);
41
- }
42
-
43
- /** Treat an `InterfacesAdded` body (`[path, interfaces]`) as one decoded object. */
44
- export function asAddedObject(path: DbusValue, interfaces: DbusValue): DecodedObject {
45
- if (typeof path !== 'string' || !Array.isArray(interfaces)) {
46
- throw new TypeError('InterfacesAdded body is not [objectPath, interfaces]');
47
- }
48
- return [path, interfaces as unknown as DecodedInterfaces];
49
- }
50
-
51
- /** Every object path in the tree, in wire order. */
52
- export function objectPaths(tree: DecodedManagedObjects): string[] {
53
- return tree.map(([path]) => path);
54
- }
55
-
56
- /** The object at `path`, or `undefined`. */
57
- export function findObject(tree: DecodedManagedObjects, path: string): DecodedObject | undefined {
58
- return tree.find(([objectPath]) => objectPath === path);
59
- }
60
-
61
- /** The property entries of one interface on one object, or `undefined`. */
62
- export function findInterface(
63
- tree: DecodedManagedObjects,
64
- path: string,
65
- iface: string,
66
- ): DecodedProps | undefined {
67
- return findObject(tree, path)?.[1].find(([name]) => name === iface)?.[1];
68
- }
69
-
70
- /** Object paths that carry a given interface. */
71
- export function pathsWithInterface(tree: DecodedManagedObjects, iface: string): string[] {
72
- return tree
73
- .filter(([, interfaces]) => interfaces.some(([name]) => name === iface))
74
- .map(([path]) => path);
75
- }
76
-
77
- /** Whether an object exposes a given interface. */
78
- export function hasInterface(tree: DecodedManagedObjects, path: string, iface: string): boolean {
79
- return findInterface(tree, path, iface) !== undefined;
80
- }
81
-
82
- /** The inner value of a property (a variant's `.value`), or `undefined`. */
83
- export function propValue(props: DecodedProps | undefined, name: string): DbusValue | undefined {
84
- return props?.find(([key]) => key === name)?.[1]?.value;
85
- }
86
-
87
- /** A string-typed property, or `undefined` if absent / not a string. */
88
- export function stringProp(props: DecodedProps | undefined, name: string): string | undefined {
89
- const value = propValue(props, name);
90
- return typeof value === 'string' ? value : undefined;
91
- }
92
-
93
- /** A number-typed property, or `undefined` if absent / not a number. */
94
- export function numberProp(props: DecodedProps | undefined, name: string): number | undefined {
95
- const value = propValue(props, name);
96
- return typeof value === 'number' ? value : undefined;
97
- }
98
-
99
- /** Resolve an object-path property (e.g. a modem's `Sim`) to that object's props. */
100
- export function followObjectPath(
101
- tree: DecodedManagedObjects,
102
- props: DecodedProps | undefined,
103
- propName: string,
104
- iface: string,
105
- ): DecodedProps | undefined {
106
- const target = propValue(props, propName);
107
- return typeof target === 'string' ? findInterface(tree, target, iface) : undefined;
108
- }
@@ -1,160 +0,0 @@
1
- // Pure mapping: a decoded ModemManager object tree → a `CellularSnapshot`.
2
- //
3
- // A3.1 is lifecycle-only. This mapper is DELIBERATELY conservative: it captures
4
- // identity, presence, source health, radio power, and MM state — the facts the
5
- // observer needs to order and reconcile modems — but leaves the richer 3GPP
6
- // registration + access-technology set as `unknown`/empty. Faithful registration and
7
- // cell-info normalisation are A3.2 (identity ladder) and A3.3 (Signal.Setup / cell
8
- // info); mapping them here would either be a guess or trip the domain guards. The
9
- // snapshot this produces is always guard-valid by construction.
10
-
11
- import {
12
- type CellularSnapshot,
13
- imeiEquipmentId,
14
- type MmState,
15
- subscriptionId as makeSubscriptionId,
16
- type RadioPower,
17
- runtimePath,
18
- type SubscriptionId,
19
- } from '../domain';
20
- import { MODEM_IFACE, MODEM3GPP_IFACE, SIM_IFACE } from './constants';
21
- import {
22
- type DecodedManagedObjects,
23
- findInterface,
24
- followObjectPath,
25
- numberProp,
26
- pathsWithInterface,
27
- stringProp,
28
- } from './managed-objects';
29
-
30
- /** The dimensions of a mapped modem, WITHOUT a revision (the observer stamps that). */
31
- export type MappedModem = Omit<CellularSnapshot, 'revision'>;
32
-
33
- /** MMModemState (`Modem.State`, signed) → the domain `MmState`. */
34
- function mapMmState(state: number | undefined): MmState {
35
- switch (state) {
36
- case -1:
37
- return 'failed';
38
- case 1:
39
- return 'initializing';
40
- case 2:
41
- return 'locked';
42
- case 3:
43
- return 'disabled';
44
- case 4:
45
- return 'disabling';
46
- case 5:
47
- return 'enabling';
48
- case 6:
49
- return 'enabled';
50
- case 7:
51
- return 'searching';
52
- case 8:
53
- return 'registered';
54
- case 9:
55
- return 'disconnecting';
56
- case 10:
57
- return 'connecting';
58
- case 11:
59
- return 'connected';
60
- default:
61
- return 'unknown';
62
- }
63
- }
64
-
65
- /** MMModemPowerState (`Modem.PowerState`) → the domain `RadioPower`. */
66
- function mapRadioPower(power: number | undefined): RadioPower {
67
- switch (power) {
68
- case 1:
69
- return 'off';
70
- case 2:
71
- return 'low';
72
- case 3:
73
- return 'on';
74
- default:
75
- return 'unknown';
76
- }
77
- }
78
-
79
- /** Locked / failed modems keep the radio off; every other state we cannot see as
80
- * off (the guards forbid an active MM state with the radio off), so an unknown
81
- * power reading is treated as `on` when the modem is clearly on the air. */
82
- function reconcilePower(power: RadioPower, state: MmState): RadioPower {
83
- const onTheAir =
84
- state === 'enabled' ||
85
- state === 'searching' ||
86
- state === 'registered' ||
87
- state === 'connecting' ||
88
- state === 'connected' ||
89
- state === 'disconnecting';
90
- if (onTheAir && (power === 'unknown' || power === 'off')) {
91
- return 'on';
92
- }
93
- return power;
94
- }
95
-
96
- /** Read a modem's subscription id (ICCID) from its active SIM object, if any. */
97
- function readSubscriptionId(
98
- tree: DecodedManagedObjects,
99
- modemPath: string,
100
- ): SubscriptionId | undefined {
101
- const modem = findInterface(tree, modemPath, MODEM_IFACE);
102
- const sim = followObjectPath(tree, modem, 'Sim', SIM_IFACE);
103
- const iccid = stringProp(sim, 'SimIdentifier');
104
- return iccid !== undefined && iccid.length > 0 ? makeSubscriptionId(iccid) : undefined;
105
- }
106
-
107
- /** Map ONE modem object to its dimensions. The modem must expose `Modem`. */
108
- export function mapModem(tree: DecodedManagedObjects, modemPath: string): MappedModem {
109
- const modem = findInterface(tree, modemPath, MODEM_IFACE);
110
- const modem3gpp = findInterface(tree, modemPath, MODEM3GPP_IFACE);
111
-
112
- const equipment = stringProp(modem, 'EquipmentIdentifier') ?? stringProp(modem3gpp, 'Imei') ?? '';
113
- const mmState = mapMmState(numberProp(modem, 'State'));
114
- const radioPower = reconcilePower(mapRadioPower(numberProp(modem, 'PowerState')), mmState);
115
- const sub = readSubscriptionId(tree, modemPath);
116
-
117
- return {
118
- identity: {
119
- equipmentId: imeiEquipmentId(equipment),
120
- runtimePath: runtimePath(modemPath),
121
- ...(sub !== undefined ? { subscriptionId: sub } : {}),
122
- },
123
- presence: 'present',
124
- sourceHealth: 'live',
125
- simSlots: [],
126
- radioPower,
127
- mmState,
128
- // Conservative: 3GPP registration + RAT set are A3.3's job (see file header).
129
- registration: { status: 'unknown', activeRats: new Set() },
130
- nmActivation: 'unavailable',
131
- dataInterface: { present: false },
132
- reconcileStatus: 'pending',
133
- recoveryState: { stage: 'idle', attempts: 0 },
134
- };
135
- }
136
-
137
- /** Every modem path in the tree (objects exposing the `Modem` interface), in order. */
138
- export function modemPaths(tree: DecodedManagedObjects): string[] {
139
- return pathsWithInterface(tree, MODEM_IFACE);
140
- }
141
-
142
- /** A stable fingerprint of a mapped modem's meaningful dimensions (ignores revision
143
- * and source health), used to suppress redundant revision bumps on identical reads. */
144
- export function fingerprint(mapped: MappedModem): string {
145
- return JSON.stringify({
146
- id: mapped.identity.equipmentId,
147
- sub: mapped.identity.subscriptionId ?? null,
148
- path: mapped.identity.runtimePath,
149
- presence: mapped.presence,
150
- radioPower: mapped.radioPower,
151
- mmState: mapped.mmState,
152
- registration: {
153
- status: mapped.registration.status,
154
- rats: [...mapped.registration.activeRats].sort(),
155
- },
156
- nmActivation: mapped.nmActivation,
157
- dataInterface: mapped.dataInterface,
158
- reconcileStatus: mapped.reconcileStatus,
159
- });
160
- }