@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
@@ -0,0 +1,118 @@
1
+ import { epochMillis, runtimePath } from '../../domain/index.js';
2
+ import { resolveFccUnlockCoverage } from '../../fcc/index.js';
3
+ import { advanceGnssFixState, GNSS_OFF } from '../../location/index.js';
4
+ import { createDbusSmsPort } from '../../sms/index.js';
5
+ export class ModemManagerModuleOperations {
6
+ operations;
7
+ #options;
8
+ #smsPorts = new Map();
9
+ #locationStates = new Map();
10
+ constructor(options) {
11
+ this.#options = options;
12
+ this.operations = {
13
+ location: {
14
+ status: async (context) => {
15
+ const path = await this.#modemPath(context);
16
+ return path === undefined
17
+ ? { ok: false, reason: 'modem-not-found' }
18
+ : this.#options.location.getLocationStatus(runtimePath(path));
19
+ },
20
+ enable: async (context, sources) => {
21
+ const path = await this.#modemPath(context);
22
+ if (path === undefined)
23
+ return this.#unsupportedToggle();
24
+ const result = await this.#options.location.enableGnss(runtimePath(path), sources);
25
+ if (result.outcome === 'applied') {
26
+ this.#setLocationState(context, {
27
+ kind: 'gnss-enabled',
28
+ at: epochMillis(this.#options.now()),
29
+ });
30
+ }
31
+ return result;
32
+ },
33
+ disable: async (context) => {
34
+ const path = await this.#modemPath(context);
35
+ if (path === undefined)
36
+ return this.#unsupportedToggle();
37
+ const result = await this.#options.location.disableGnss(runtimePath(path));
38
+ if (result.outcome === 'applied')
39
+ this.#setLocationState(context, { kind: 'gnss-disabled' });
40
+ return result;
41
+ },
42
+ readFix: async (context) => {
43
+ const path = await this.#modemPath(context);
44
+ if (path === undefined)
45
+ return { outcome: 'unsupported', reason: 'modem-not-found' };
46
+ const read = await this.#options.location.readFix(runtimePath(path));
47
+ this.#setLocationState(context, {
48
+ kind: 'read',
49
+ at: epochMillis(this.#options.now()),
50
+ read,
51
+ });
52
+ return read;
53
+ },
54
+ state: (context) => this.#locationStates.get(String(context.physicalModemId)) ?? GNSS_OFF,
55
+ tick: (context) => this.#setLocationState(context, {
56
+ kind: 'tick',
57
+ at: epochMillis(this.#options.now()),
58
+ }),
59
+ },
60
+ sms: (context) => this.#sms(context),
61
+ ussd: options.ussd,
62
+ initiateUssd: (context, ussdCommand) => this.#ussd(context, (path) => options.ussd.initiate(runtimePath(path), ussdCommand)),
63
+ respondUssd: (context, ussdResponse) => this.#ussd(context, (path) => options.ussd.respond(runtimePath(path), ussdResponse)),
64
+ cancelUssd: (context) => this.#ussd(context, (path) => options.ussd.cancel(runtimePath(path))),
65
+ fccCoverage: resolveFccUnlockCoverage,
66
+ };
67
+ }
68
+ async stop() {
69
+ for (const port of this.#smsPorts.values())
70
+ await port.stop();
71
+ this.#smsPorts.clear();
72
+ this.#options.ussd.stop();
73
+ }
74
+ async #sms(context) {
75
+ const snapshot = await this.#options.readSnapshot(context);
76
+ if (!snapshot.ok)
77
+ return { ok: false, reason: snapshot.reason };
78
+ if (!snapshot.capabilities.sms)
79
+ return { ok: false, reason: 'unsupported' };
80
+ let port = this.#smsPorts.get(snapshot.modemPath);
81
+ if (port === undefined) {
82
+ port = createDbusSmsPort({
83
+ transport: this.#options.transport,
84
+ modemPath: snapshot.modemPath,
85
+ destination: this.#options.destination,
86
+ });
87
+ this.#smsPorts.set(snapshot.modemPath, port);
88
+ }
89
+ return { ok: true, port };
90
+ }
91
+ async #ussd(context, run) {
92
+ const path = await this.#modemPath(context);
93
+ return path === undefined
94
+ ? {
95
+ ok: false,
96
+ snapshot: this.#options.ussd.snapshot(runtimePath('/')),
97
+ refusal: 'unsupported',
98
+ }
99
+ : run(path);
100
+ }
101
+ async #modemPath(context) {
102
+ const snapshot = await this.#options.readSnapshot(context);
103
+ return snapshot.ok ? snapshot.modemPath : undefined;
104
+ }
105
+ #setLocationState(context, event) {
106
+ const key = String(context.physicalModemId);
107
+ const next = advanceGnssFixState(this.#locationStates.get(key) ?? GNSS_OFF, event);
108
+ this.#locationStates.set(key, next);
109
+ return next;
110
+ }
111
+ #unsupportedToggle() {
112
+ return {
113
+ outcome: 'unsupported',
114
+ reason: 'modem-not-found',
115
+ enabledSources: new Set(),
116
+ };
117
+ }
118
+ }
@@ -0,0 +1,39 @@
1
+ import { type MmDbusBackend, type QuiesceHook } from '../../backend/index.js';
2
+ import { type BandCertificationCatalog, type BandSku } from '../../band/index.js';
3
+ import { type NormalizedModemObservation } from '../../observations/index.js';
4
+ import type { ObservationListener } from '../../ports/index.js';
5
+ import type { DbusTransport } from '../../transport/index.js';
6
+ import type { ProviderDefinition, ProviderExecutionContext } from '../contracts.js';
7
+ import type { ModemManagerProviderLifecycle, ModemManagerProviderOperations, ModemManagerSnapshotResult } from './types.js';
8
+ export interface ModemManagerProviderOptions {
9
+ readonly transport: DbusTransport;
10
+ readonly destination?: string;
11
+ readonly quiesce?: QuiesceHook;
12
+ readonly now?: () => number;
13
+ /**
14
+ * The band-lock certification catalog. Defaults to the one shipped in this package,
15
+ * which is EMPTY — so a band write is refused on every device until a human-reviewed
16
+ * commit adds an entry carrying its bench transcript.
17
+ */
18
+ readonly bandCertificationCatalog?: BandCertificationCatalog;
19
+ /**
20
+ * The device's SKU, if the embedding process can resolve one.
21
+ *
22
+ * ModemManager's `Modem` interface carries `Model` and `Revision` but NO USB
23
+ * `vid:pid`, and `BandSku` is keyed on all three — so this package structurally
24
+ * cannot build one from the bus alone, and a partial match would certify a family
25
+ * no reviewer looked at. With no resolver injected there is no SKU, hence no entry,
26
+ * hence no band write: fail-closed, which is this module's whole stance.
27
+ */
28
+ readonly bandSku?: (context: ProviderExecutionContext) => BandSku | undefined;
29
+ }
30
+ export declare class ModemManagerProvider implements ModemManagerProviderLifecycle {
31
+ #private;
32
+ readonly definition: ProviderDefinition<NormalizedModemObservation, ModemManagerProviderOperations>;
33
+ constructor(options: ModemManagerProviderOptions);
34
+ start(): ReturnType<MmDbusBackend['start']>;
35
+ observe(listener: ObservationListener): () => void;
36
+ stop(): Promise<void>;
37
+ readSnapshot(context: ProviderExecutionContext): Promise<ModemManagerSnapshotResult>;
38
+ }
39
+ export declare function createModemManagerProvider(options: ModemManagerProviderOptions): ModemManagerProvider;
@@ -0,0 +1,152 @@
1
+ import { createMmDbusBackend, fetchManagedObjects, MM_BUS_NAME, MmLocation, ModemActor, } from '../../backend/index.js';
2
+ import { BAND_CERTIFICATION_CATALOG, findBandCertification, } from '../../band/index.js';
3
+ import { epochMillis, sourceEpoch, stableKeyFromPhysicalModemId, } from '../../domain/index.js';
4
+ import { unavailableObservation } from '../../observations/index.js';
5
+ import { MmUssd } from '../../ussd/index.js';
6
+ import { mapModemManagerError } from './errors.js';
7
+ import { createGenericOperations } from './generic-operations.js';
8
+ import { ModemManagerModuleOperations } from './module-operations.js';
9
+ import { buildModemManagerSnapshot } from './snapshot.js';
10
+ const PROFILE = 'generic-mm';
11
+ export class ModemManagerProvider {
12
+ definition;
13
+ #transport;
14
+ #destination;
15
+ #now;
16
+ #backend;
17
+ #bandCatalog;
18
+ #bandSku;
19
+ #stableKeyByPath = new Map();
20
+ #moduleOperations;
21
+ #startPromise;
22
+ #epoch = 1;
23
+ constructor(options) {
24
+ this.#transport = options.transport;
25
+ this.#destination = options.destination ?? MM_BUS_NAME;
26
+ this.#now = options.now ?? Date.now;
27
+ this.#bandCatalog = options.bandCertificationCatalog ?? BAND_CERTIFICATION_CATALOG;
28
+ this.#bandSku = options.bandSku ?? (() => undefined);
29
+ const actor = new ModemActor(options.quiesce);
30
+ const resolveStableKey = (modem) => this.#stableKeyByPath.get(modem) ?? modem;
31
+ this.#backend = createMmDbusBackend({
32
+ transport: this.#transport,
33
+ destination: this.#destination,
34
+ actor,
35
+ now: this.#now,
36
+ });
37
+ const location = new MmLocation({
38
+ transport: this.#transport,
39
+ actor,
40
+ destination: this.#destination,
41
+ resolveStableKey,
42
+ now: this.#now,
43
+ });
44
+ const ussd = new MmUssd({
45
+ transport: this.#transport,
46
+ actor,
47
+ destination: this.#destination,
48
+ resolveStableKey,
49
+ });
50
+ this.#moduleOperations = new ModemManagerModuleOperations({
51
+ transport: this.#transport,
52
+ destination: this.#destination,
53
+ location,
54
+ ussd,
55
+ now: this.#now,
56
+ readSnapshot: (context) => this.readSnapshot(context),
57
+ });
58
+ const operations = {
59
+ access: 'read-write',
60
+ ...createGenericOperations({
61
+ backend: this.#backend,
62
+ readSnapshot: (context) => this.readSnapshot(context),
63
+ }),
64
+ ...this.#moduleOperations.operations,
65
+ };
66
+ this.definition = {
67
+ id: 'modemmanager',
68
+ profileVersion: '1',
69
+ eligibleTransports: ['modemmanager'],
70
+ passiveMatchers: [],
71
+ unauthenticatedProbes: [
72
+ { id: 'object-manager-modem', run: (request) => this.#probe(request) },
73
+ ],
74
+ capabilityReaders: [
75
+ { id: 'runtime-modem-interface', read: (context) => this.#capability(context) },
76
+ ],
77
+ observe: (context) => this.#observeNormalized(context),
78
+ operations: () => operations,
79
+ contractFixtures: [],
80
+ };
81
+ }
82
+ start() {
83
+ this.#startPromise ??= this.#backend.start();
84
+ return this.#startPromise;
85
+ }
86
+ observe(listener) {
87
+ return this.#backend.observe(listener);
88
+ }
89
+ async stop() {
90
+ await this.#moduleOperations.stop();
91
+ await this.#backend.stop();
92
+ }
93
+ async readSnapshot(context) {
94
+ try {
95
+ await this.start();
96
+ const tree = await fetchManagedObjects(this.#transport, this.#destination);
97
+ const snapshot = buildModemManagerSnapshot(tree, context, this.#now, this.#epoch, this.#bandCertification(context));
98
+ if (snapshot === undefined)
99
+ return { ok: false, reason: 'not-found' };
100
+ this.#stableKeyByPath.set(snapshot.modemPath, `modem:${context.physicalModemId}`);
101
+ return { ok: true, ...snapshot };
102
+ }
103
+ catch (error) {
104
+ return { ok: false, reason: mapModemManagerError(error).reason };
105
+ }
106
+ }
107
+ #bandCertification(context) {
108
+ const sku = this.#bandSku(context);
109
+ return sku === undefined ? undefined : findBandCertification(this.#bandCatalog, sku);
110
+ }
111
+ async #probe(request) {
112
+ const snapshot = await this.readSnapshot({ ...request, profile: PROFILE });
113
+ return {
114
+ signal: snapshot.ok
115
+ ? 'match'
116
+ : snapshot.reason === 'not-found'
117
+ ? 'mismatch'
118
+ : 'unknown',
119
+ strength: 'strong',
120
+ profiles: [PROFILE],
121
+ detail: snapshot.ok ? 'runtime-modem-interface-present' : snapshot.reason,
122
+ };
123
+ }
124
+ async #capability(context) {
125
+ const snapshot = await this.readSnapshot(context);
126
+ return {
127
+ signal: snapshot.ok
128
+ ? 'match'
129
+ : snapshot.reason === 'not-found'
130
+ ? 'mismatch'
131
+ : 'unknown',
132
+ strength: 'strong',
133
+ detail: snapshot.ok ? 'generic-controls-derived-from-runtime-properties' : snapshot.reason,
134
+ };
135
+ }
136
+ async #observeNormalized(context) {
137
+ const snapshot = await this.readSnapshot(context);
138
+ if (snapshot.ok)
139
+ return [snapshot.observation];
140
+ return [
141
+ unavailableObservation('modemmanager', {
142
+ stableKey: stableKeyFromPhysicalModemId(context.physicalModemId),
143
+ generation: context.generation,
144
+ sourceEpoch: sourceEpoch(this.#epoch),
145
+ observedAt: epochMillis(this.#now()),
146
+ }, snapshot.reason === 'not-found' ? 'device-absent' : 'provider-unavailable'),
147
+ ];
148
+ }
149
+ }
150
+ export function createModemManagerProvider(options) {
151
+ return new ModemManagerProvider(options);
152
+ }
@@ -0,0 +1,5 @@
1
+ import { type DecodedManagedObjects } from '../../backend/managed-objects.js';
2
+ import { type BandCertificationEntry } from '../../band/index.js';
3
+ import type { ProviderExecutionContext } from '../contracts.js';
4
+ import type { ModemManagerProviderSnapshot } from './types.js';
5
+ export declare function buildModemManagerSnapshot(tree: DecodedManagedObjects, context: ProviderExecutionContext, now: () => number, epoch: number, bandCertificationEntry: BandCertificationEntry | undefined): ModemManagerProviderSnapshot | undefined;
@@ -0,0 +1,204 @@
1
+ import { MODEM_IFACE, MODEM_LOCATION_IFACE, MODEM3GPP_IFACE, MODEM3GPP_USSD_IFACE, SIM_IFACE, } from '../../backend/constants.js';
2
+ import { findInterface, pathsWithInterface, propValue, } from '../../backend/managed-objects.js';
3
+ import { decodeBandList } from '../../band/index.js';
4
+ import { MESSAGING_IFACE } from '../../capability/index.js';
5
+ import { decodeStateFailedReason, epochMillis, sourceEpoch, stableKeyFromPhysicalModemId, } from '../../domain/index.js';
6
+ import { readSimPresence } from '../../hardware/router-parsers.js';
7
+ import { normalizeModemManagerObservation } from '../../observations/index.js';
8
+ import { describeBandWriteCertification, readRadioModeTruth } from '../../radio/index.js';
9
+ const SIGNAL_IFACE = `${MODEM_IFACE}.Signal`;
10
+ function rawValue(value) {
11
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean')
12
+ return value;
13
+ if (Array.isArray(value)) {
14
+ const result = [];
15
+ for (const item of value) {
16
+ const decoded = rawValue(item);
17
+ if (decoded !== undefined)
18
+ result.push(decoded);
19
+ }
20
+ return result;
21
+ }
22
+ return undefined;
23
+ }
24
+ function propsRecord(props) {
25
+ if (props === undefined)
26
+ return undefined;
27
+ const record = {};
28
+ for (const [name, wrapped] of props) {
29
+ const decoded = rawValue(wrapped.value);
30
+ if (decoded !== undefined)
31
+ record[name] = decoded;
32
+ }
33
+ return record;
34
+ }
35
+ function tuple(value) {
36
+ if (!Array.isArray(value))
37
+ return [0, 0];
38
+ const allowed = value[0];
39
+ const preferred = value[1];
40
+ return [typeof allowed === 'number' ? allowed : 0, typeof preferred === 'number' ? preferred : 0];
41
+ }
42
+ function modePairs(value) {
43
+ if (!Array.isArray(value))
44
+ return [];
45
+ const result = [];
46
+ for (const candidate of value) {
47
+ const [allowed, preferred] = tuple(candidate);
48
+ if (allowed > 0)
49
+ result.push({ allowed, preferred });
50
+ }
51
+ return result;
52
+ }
53
+ /**
54
+ * A `DbusValue` as the retention layer keeps it.
55
+ *
56
+ * `rawValue` already produces exactly this for a struct (an array of its members), so
57
+ * `SupportedModes` and `CurrentModes` reach the verbatim decoder in the same shape the
58
+ * diagnostics block retains — one representation, so the two cannot disagree.
59
+ */
60
+ function structValue(value) {
61
+ return value === undefined ? undefined : rawValue(value);
62
+ }
63
+ function signalState(modem, signal) {
64
+ const quality = tuple(propValue(modem, 'SignalQuality'));
65
+ return {
66
+ ...(quality[0] >= 0 ? { quality: quality[0] } : {}),
67
+ ...(Array.isArray(propValue(modem, 'SignalQuality')) ? { recent: quality[1] !== 0 } : {}),
68
+ extendedAvailable: signal !== undefined,
69
+ };
70
+ }
71
+ function simState(tree, modem) {
72
+ const activePath = propValue(modem, 'Sim');
73
+ const slots = propValue(modem, 'SimSlots');
74
+ const paths = Array.isArray(slots)
75
+ ? slots.filter((value) => typeof value === 'string' && value !== '/')
76
+ : [];
77
+ const active = typeof activePath === 'string' ? findInterface(tree, activePath, SIM_IFACE) : undefined;
78
+ const lockRequired = propValue(modem, 'UnlockRequired');
79
+ const rawFailedReason = propValue(modem, 'StateFailedReason');
80
+ const failedReason = typeof rawFailedReason === 'number'
81
+ ? decodeStateFailedReason(rawFailedReason)
82
+ : typeof rawFailedReason === 'string'
83
+ ? rawFailedReason
84
+ : undefined;
85
+ const primarySlot = propValue(modem, 'PrimarySimSlot');
86
+ const simType = propValue(active, 'SimType');
87
+ const esimStatus = propValue(active, 'EsimStatus');
88
+ const reading = readSimPresence({
89
+ ...(typeof activePath === 'string' ? { sim: activePath } : {}),
90
+ ...(paths.length > 0 ? { simSlots: paths } : {}),
91
+ ...(failedReason === undefined ? {} : { failedReason }),
92
+ });
93
+ return {
94
+ // POSITIVE evidence only: an exported SIM object path proves a SIM. Its ABSENCE
95
+ // proves nothing — `presence` below is the answer to "is there a SIM", and it
96
+ // says `unknown` unless the modem stated `sim-missing` itself.
97
+ present: typeof activePath === 'string' && activePath !== '/',
98
+ presence: reading.presence,
99
+ presenceEvidence: reading.evidence,
100
+ slotCount: paths.length,
101
+ primarySlot: typeof primarySlot === 'number' ? primarySlot : 0,
102
+ ...(typeof lockRequired === 'number' ? { lockRequired } : {}),
103
+ ...(typeof simType === 'number' ? { simType } : {}),
104
+ ...(typeof esimStatus === 'number' ? { esimStatus } : {}),
105
+ };
106
+ }
107
+ function radioPower(value) {
108
+ switch (value) {
109
+ case 1:
110
+ return 'off';
111
+ case 2:
112
+ return 'low';
113
+ case 3:
114
+ return 'on';
115
+ default:
116
+ return 'unknown';
117
+ }
118
+ }
119
+ function hasProperty(props, name) {
120
+ return props.some(([property]) => property === name);
121
+ }
122
+ function findModemPath(tree, context) {
123
+ const [kind, ...parts] = String(context.physicalModemId).split(':');
124
+ const expected = parts.join(':');
125
+ for (const path of pathsWithInterface(tree, MODEM_IFACE)) {
126
+ const modem = findInterface(tree, path, MODEM_IFACE);
127
+ const candidates = kind === 'serial'
128
+ ? [propValue(modem, 'DeviceIdentifier')]
129
+ : [propValue(modem, 'Device'), propValue(modem, 'Physdev')];
130
+ if (candidates.some((candidate) => candidate === expected))
131
+ return path;
132
+ }
133
+ return undefined;
134
+ }
135
+ export function buildModemManagerSnapshot(tree, context, now, epoch, bandCertificationEntry) {
136
+ const modemPath = findModemPath(tree, context);
137
+ if (modemPath === undefined)
138
+ return undefined;
139
+ const modem = findInterface(tree, modemPath, MODEM_IFACE);
140
+ if (modem === undefined)
141
+ return undefined;
142
+ const modem3gpp = findInterface(tree, modemPath, MODEM3GPP_IFACE);
143
+ const signal = findInterface(tree, modemPath, SIGNAL_IFACE);
144
+ const activePath = propValue(modem, 'Sim');
145
+ const sim = typeof activePath === 'string' ? findInterface(tree, activePath, SIM_IFACE) : undefined;
146
+ const interfaces = tree.find(([path]) => path === modemPath)?.[1] ?? [];
147
+ const interfaceNames = new Set(interfaces.map(([name]) => name));
148
+ const slots = propValue(modem, 'SimSlots');
149
+ const bandCertification = describeBandWriteCertification({
150
+ entry: bandCertificationEntry,
151
+ supported: decodeBandList(propValue(modem, 'SupportedBands')),
152
+ });
153
+ const capabilities = {
154
+ modeRead: hasProperty(modem, 'CurrentModes'),
155
+ modeWrite: hasProperty(modem, 'CurrentModes'),
156
+ bandRead: hasProperty(modem, 'SupportedBands'),
157
+ bandWrite: hasProperty(modem, 'SupportedBands') &&
158
+ bandCertification.satisfied &&
159
+ bandCertification.offerable.length > 0,
160
+ signalRead: hasProperty(modem, 'SignalQuality') || signal !== undefined,
161
+ simRead: hasProperty(modem, 'Sim') || hasProperty(modem, 'SimSlots'),
162
+ multiSim: Array.isArray(slots) && slots.filter((entry) => entry !== '/').length > 1,
163
+ location: interfaceNames.has(MODEM_LOCATION_IFACE),
164
+ sms: interfaceNames.has(MESSAGING_IFACE),
165
+ ussd: interfaceNames.has(MODEM3GPP_USSD_IFACE),
166
+ powerRead: hasProperty(modem, 'PowerState'),
167
+ };
168
+ const [allowed, preferred] = tuple(propValue(modem, 'CurrentModes'));
169
+ const modeTruth = readRadioModeTruth({
170
+ currentModes: structValue(propValue(modem, 'CurrentModes')),
171
+ supportedModes: structValue(propValue(modem, 'SupportedModes')),
172
+ });
173
+ const normalizationContext = {
174
+ stableKey: stableKeyFromPhysicalModemId(context.physicalModemId),
175
+ generation: context.generation,
176
+ sourceEpoch: sourceEpoch(epoch),
177
+ observedAt: epochMillis(now()),
178
+ };
179
+ // The struct properties are handed to normalization VERBATIM — `CurrentModes` as its
180
+ // `(uu)` pair, `SignalQuality` as its `(ub)` pair. Flattening them here (which this
181
+ // did) kept the first member and dropped the preferred mode and the recency flag
182
+ // before the diagnostics block ever saw them, which is a drop no downstream layer
183
+ // can undo. The normalizer reads either shape.
184
+ const modemRaw = propsRecord(modem) ?? {};
185
+ return {
186
+ modemPath,
187
+ capabilities,
188
+ bandCertification,
189
+ radio: {
190
+ current: { allowed, preferred },
191
+ supported: modePairs(propValue(modem, 'SupportedModes')),
192
+ truth: modeTruth,
193
+ },
194
+ signal: signalState(modem, signal),
195
+ sim: simState(tree, modem),
196
+ power: radioPower(propValue(modem, 'PowerState')),
197
+ observation: normalizeModemManagerObservation({
198
+ modem: modemRaw,
199
+ ...(modem3gpp === undefined ? {} : { modem3gpp: propsRecord(modem3gpp) ?? {} }),
200
+ ...(sim === undefined ? {} : { sim: propsRecord(sim) ?? {} }),
201
+ ...(signal === undefined ? {} : { signal: propsRecord(signal) ?? {} }),
202
+ }, normalizationContext),
203
+ };
204
+ }
@@ -0,0 +1,135 @@
1
+ import type { DesiredRadio, ObservationEnvelope, OperationDescriptor, OperationResult, RadioPower } from '../../domain/index.js';
2
+ import type { SimPresence, SimPresenceEvidence } from '../../hardware/router-parsers.js';
3
+ import type { GnssFixState } from '../../location/index.js';
4
+ import type { NormalizedModemObservation } from '../../observations/index.js';
5
+ import type { FixRead, GnssSource, LocationStatusResult, LocationToggleResult, ModemBands, ObservationList, ObservationListener, SmsObservationPort } from '../../ports/index.js';
6
+ import type { BandWriteCertification, ModeSelection, RadioModeTruth } from '../../radio/index.js';
7
+ import type { MmUssd, UssdVerbResult } from '../../ussd/index.js';
8
+ import type { ProviderExecutionContext, ProviderOperationsSurface } from '../contracts.js';
9
+ import type { ModemManagerRefusalReason } from './errors.js';
10
+ export type ModemManagerCapabilities = {
11
+ readonly modeRead: boolean;
12
+ readonly modeWrite: boolean;
13
+ readonly bandRead: boolean;
14
+ readonly bandWrite: boolean;
15
+ readonly signalRead: boolean;
16
+ readonly simRead: boolean;
17
+ readonly multiSim: boolean;
18
+ readonly location: boolean;
19
+ readonly sms: boolean;
20
+ readonly ussd: boolean;
21
+ readonly powerRead: boolean;
22
+ };
23
+ export type ModemManagerRadioState = {
24
+ readonly current: {
25
+ readonly allowed: number;
26
+ readonly preferred: number;
27
+ };
28
+ readonly supported: readonly {
29
+ readonly allowed: number;
30
+ readonly preferred: number;
31
+ }[];
32
+ /**
33
+ * The SAME properties decoded without loss — `preferred: 'none'` stays `none`, an
34
+ * unfamiliar mode bit stays offerable as `unknown-combination`, and a member that
35
+ * is not a `(uu)` lands in `undecodable` rather than vanishing. `supported` above
36
+ * is the pre-existing raw-mask view and DROPS a zero-allowed member; this one does
37
+ * not, which is the whole point of carrying both.
38
+ */
39
+ readonly truth: RadioModeTruth;
40
+ };
41
+ export type ModemManagerSignalState = {
42
+ readonly quality?: number;
43
+ readonly recent?: boolean;
44
+ readonly extendedAvailable: boolean;
45
+ };
46
+ export type ModemManagerSimState = {
47
+ /**
48
+ * The modem exports an ACTIVE SIM object path. `true` is positive evidence of a
49
+ * SIM; `false` is NOT evidence of absence — read `presence` for that.
50
+ */
51
+ readonly present: boolean;
52
+ /** `absent` only ever comes from `StateFailedReason: sim-missing`. */
53
+ readonly presence: SimPresence;
54
+ readonly presenceEvidence: SimPresenceEvidence;
55
+ readonly slotCount: number;
56
+ readonly primarySlot: number;
57
+ readonly lockRequired?: number;
58
+ readonly simType?: number;
59
+ readonly esimStatus?: number;
60
+ };
61
+ export type ModemManagerProviderSnapshot = {
62
+ readonly modemPath: string;
63
+ readonly capabilities: ModemManagerCapabilities;
64
+ readonly radio: ModemManagerRadioState;
65
+ /** The band-lock gate for THIS device, resolved from the shipped certification catalog. */
66
+ readonly bandCertification: BandWriteCertification;
67
+ readonly signal: ModemManagerSignalState;
68
+ readonly sim: ModemManagerSimState;
69
+ readonly power: RadioPower;
70
+ readonly observation: ObservationEnvelope<NormalizedModemObservation>;
71
+ };
72
+ export type ModemManagerSnapshotResult = ({
73
+ readonly ok: true;
74
+ } & ModemManagerProviderSnapshot) | {
75
+ readonly ok: false;
76
+ readonly reason: ModemManagerRefusalReason;
77
+ };
78
+ export interface ContextReadOperation<O> {
79
+ readonly descriptor: OperationDescriptor<never, O>;
80
+ read(context: ProviderExecutionContext): Promise<OperationResult<O>>;
81
+ }
82
+ export interface ContextWriteOperation<I, O> {
83
+ /** The shape-only descriptor: what this operation is, before any device answered. */
84
+ readonly descriptor: OperationDescriptor<I, O>;
85
+ /**
86
+ * The descriptor as the LIVE device entitles it.
87
+ *
88
+ * A static descriptor cannot carry a device's own catalog, so it cannot say which
89
+ * mode combinations this modem advertises or whether this SKU's band lock is
90
+ * certified. Those are exactly the facts a consumer needs before it offers a
91
+ * control, so they are read here instead of being inferred from a capability flag.
92
+ */
93
+ describe(context: ProviderExecutionContext): Promise<OperationDescriptor<I, O>>;
94
+ read(context: ProviderExecutionContext): Promise<OperationResult<O>>;
95
+ write(context: ProviderExecutionContext, input: I): Promise<OperationResult<O>>;
96
+ }
97
+ export type SmsPortResult = {
98
+ readonly ok: true;
99
+ readonly port: SmsObservationPort;
100
+ } | {
101
+ readonly ok: false;
102
+ readonly reason: ModemManagerRefusalReason;
103
+ };
104
+ export interface ModemManagerProviderOperations extends ProviderOperationsSurface {
105
+ readonly radio: ContextWriteOperation<DesiredRadio, ModemManagerRadioState>;
106
+ /**
107
+ * The modem's OWN mode vocabulary — an advertised `(allowed, preferred)` pair,
108
+ * selected verbatim. Separate from `radio` because `DesiredRadio` is an ordered RAT
109
+ * preference and cannot express `preferred: none`, which real hardware advertises.
110
+ */
111
+ readonly modes: ContextWriteOperation<ModeSelection, RadioModeTruth>;
112
+ readonly bands: ContextWriteOperation<readonly string[], ModemBands>;
113
+ readonly signal: ContextReadOperation<ModemManagerSignalState>;
114
+ readonly sim: ContextReadOperation<ModemManagerSimState>;
115
+ readonly power: ContextReadOperation<RadioPower>;
116
+ readonly location: {
117
+ status(context: ProviderExecutionContext): Promise<LocationStatusResult>;
118
+ enable(context: ProviderExecutionContext, sources: readonly GnssSource[]): Promise<LocationToggleResult>;
119
+ disable(context: ProviderExecutionContext): Promise<LocationToggleResult>;
120
+ readFix(context: ProviderExecutionContext): Promise<FixRead>;
121
+ state(context: ProviderExecutionContext): GnssFixState;
122
+ tick(context: ProviderExecutionContext): GnssFixState;
123
+ };
124
+ sms(context: ProviderExecutionContext): Promise<SmsPortResult>;
125
+ readonly ussd: MmUssd;
126
+ initiateUssd(context: ProviderExecutionContext, ussdCommand: string): Promise<UssdVerbResult>;
127
+ respondUssd(context: ProviderExecutionContext, ussdResponse: string): Promise<UssdVerbResult>;
128
+ cancelUssd(context: ProviderExecutionContext): Promise<UssdVerbResult>;
129
+ readonly fccCoverage: (vid: string | undefined, pid: string | undefined) => 'present' | 'absent' | 'unknown';
130
+ }
131
+ export interface ModemManagerProviderLifecycle {
132
+ start(): Promise<ObservationList>;
133
+ observe(listener: ObservationListener): () => void;
134
+ stop(): Promise<void>;
135
+ }
@@ -0,0 +1 @@
1
+ export {};