@ceralive/modem-control 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +341 -0
  2. package/dist/backend/at-lease.d.ts +59 -0
  3. package/dist/backend/at-lease.js +118 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +101 -0
  61. package/dist/backend/transition-preconditions.js +132 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +216 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +20 -0
  146. package/dist/index.js +27 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +61 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operation-ids.d.ts +2 -0
  196. package/dist/operation-ids.js +26 -0
  197. package/dist/operations/contracts.d.ts +72 -0
  198. package/dist/operations/contracts.js +1 -0
  199. package/dist/operations/index.d.ts +1 -0
  200. package/dist/operations/index.js +1 -0
  201. package/dist/operations/operation-engine.d.ts +16 -0
  202. package/dist/operations/operation-engine.js +194 -0
  203. package/dist/ports/index.d.ts +12 -0
  204. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  205. package/dist/ports/location.d.ts +87 -0
  206. package/dist/ports/location.js +36 -0
  207. package/dist/ports/modem-manager.d.ts +89 -0
  208. package/dist/ports/modem-manager.js +9 -0
  209. package/dist/ports/mutation-admission.d.ts +27 -0
  210. package/dist/ports/mutation-admission.js +9 -0
  211. package/dist/ports/network-manager.d.ts +68 -0
  212. package/dist/ports/network-manager.js +13 -0
  213. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  214. package/dist/ports/observation.js +7 -0
  215. package/dist/ports/ops.d.ts +44 -0
  216. package/dist/ports/ops.js +16 -0
  217. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  218. package/dist/ports/receipts.js +9 -0
  219. package/dist/ports/reconcile.d.ts +33 -0
  220. package/dist/ports/reconcile.js +200 -0
  221. package/dist/ports/resource-ownership.d.ts +29 -0
  222. package/dist/ports/resource-ownership.js +1 -0
  223. package/dist/ports/router.d.ts +19 -0
  224. package/dist/ports/router.js +7 -0
  225. package/dist/ports/sms.d.ts +64 -0
  226. package/dist/ports/sms.js +24 -0
  227. package/dist/ports/uhubctl.d.ts +6 -0
  228. package/dist/ports/uhubctl.js +1 -0
  229. package/dist/providers/contracts.d.ts +124 -0
  230. package/dist/providers/contracts.js +10 -0
  231. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  232. package/dist/providers/huawei-hilink/index.js +2 -0
  233. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  234. package/dist/providers/huawei-hilink/operations.js +56 -0
  235. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  236. package/dist/providers/huawei-hilink/provider.js +76 -0
  237. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  238. package/dist/providers/huawei-hilink/runtime.js +171 -0
  239. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  240. package/dist/providers/huawei-hilink/session.js +120 -0
  241. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  242. package/dist/providers/huawei-hilink/transport.js +1 -0
  243. package/dist/providers/index.d.ts +8 -0
  244. package/dist/providers/index.js +8 -0
  245. package/dist/providers/matcher.d.ts +3 -0
  246. package/dist/providers/matcher.js +205 -0
  247. package/dist/providers/modem-manager/errors.d.ts +7 -0
  248. package/dist/providers/modem-manager/errors.js +37 -0
  249. package/dist/providers/modem-manager/generic-operations.d.ts +10 -0
  250. package/dist/providers/modem-manager/generic-operations.js +209 -0
  251. package/dist/providers/modem-manager/index.d.ts +4 -0
  252. package/dist/providers/modem-manager/index.js +4 -0
  253. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  254. package/dist/providers/modem-manager/module-operations.js +118 -0
  255. package/dist/providers/modem-manager/provider.d.ts +41 -0
  256. package/dist/providers/modem-manager/provider.js +155 -0
  257. package/dist/providers/modem-manager/runtime-composition-operation.d.ts +32 -0
  258. package/dist/providers/modem-manager/runtime-composition-operation.js +151 -0
  259. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  260. package/dist/providers/modem-manager/snapshot.js +204 -0
  261. package/dist/providers/modem-manager/types.d.ts +137 -0
  262. package/dist/providers/modem-manager/types.js +1 -0
  263. package/dist/providers/network-manager/adapter.d.ts +71 -0
  264. package/dist/providers/network-manager/adapter.js +348 -0
  265. package/dist/providers/network-manager/index.d.ts +2 -0
  266. package/dist/providers/network-manager/index.js +2 -0
  267. package/dist/providers/network-manager/types.d.ts +171 -0
  268. package/dist/providers/network-manager/types.js +77 -0
  269. package/dist/providers/registry.d.ts +13 -0
  270. package/dist/providers/registry.js +33 -0
  271. package/dist/providers/ufi-himi/index.d.ts +6 -0
  272. package/dist/providers/ufi-himi/index.js +6 -0
  273. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  274. package/dist/providers/ufi-himi/operations.js +66 -0
  275. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  276. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  277. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  278. package/dist/providers/ufi-himi/provider.js +204 -0
  279. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  280. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  281. package/dist/providers/ufi-himi/session.d.ts +46 -0
  282. package/dist/providers/ufi-himi/session.js +92 -0
  283. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  284. package/dist/providers/ufi-himi/transport.js +25 -0
  285. package/dist/providers/zte-goform/index.d.ts +2 -0
  286. package/dist/providers/zte-goform/index.js +2 -0
  287. package/dist/providers/zte-goform/provider.d.ts +56 -0
  288. package/dist/providers/zte-goform/provider.js +101 -0
  289. package/dist/providers/zte-goform/session.d.ts +23 -0
  290. package/dist/providers/zte-goform/session.js +197 -0
  291. package/dist/providers/zte-goform/transport.d.ts +16 -0
  292. package/dist/providers/zte-goform/transport.js +1 -0
  293. package/dist/radio/band-truth.d.ts +50 -0
  294. package/dist/radio/band-truth.js +92 -0
  295. package/dist/radio/index.d.ts +3 -0
  296. package/dist/radio/index.js +10 -0
  297. package/dist/radio/mode-combinations.d.ts +88 -0
  298. package/dist/radio/mode-combinations.js +198 -0
  299. package/dist/radio/mode-truth.d.ts +67 -0
  300. package/dist/radio/mode-truth.js +112 -0
  301. package/dist/redact.d.ts +15 -0
  302. package/dist/redact.js +189 -0
  303. package/dist/safety/composition-root.d.ts +28 -0
  304. package/dist/safety/composition-root.js +65 -0
  305. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  306. package/dist/safety/flock-resource-ownership.js +138 -0
  307. package/dist/safety/index.d.ts +2 -0
  308. package/dist/safety/index.js +2 -0
  309. package/dist/sms/dbus-messaging.d.ts +17 -0
  310. package/dist/sms/dbus-messaging.js +185 -0
  311. package/dist/sms/inbox-store.d.ts +10 -0
  312. package/dist/sms/inbox-store.js +82 -0
  313. package/dist/sms/index.d.ts +4 -0
  314. package/dist/sms/index.js +10 -0
  315. package/dist/sms/mmcli-parse.d.ts +54 -0
  316. package/dist/sms/mmcli-parse.js +224 -0
  317. package/dist/sms/normalize.d.ts +42 -0
  318. package/dist/sms/normalize.js +95 -0
  319. package/dist/testing/domain-fakes.d.ts +58 -0
  320. package/dist/testing/domain-fakes.js +98 -0
  321. package/dist/testing/index.d.ts +2 -0
  322. package/dist/testing/index.js +17 -0
  323. package/dist/testing/provider-fakes.d.ts +45 -0
  324. package/dist/testing/provider-fakes.js +64 -0
  325. package/dist/transport/calls.d.ts +9 -0
  326. package/dist/transport/calls.js +88 -0
  327. package/dist/transport/codec.d.ts +3 -0
  328. package/dist/transport/codec.js +207 -0
  329. package/dist/transport/dbus-native.d.ts +57 -0
  330. package/dist/transport/dbus-native.js +17 -0
  331. package/dist/transport/errors.d.ts +21 -0
  332. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  333. package/dist/transport/index.d.ts +4 -0
  334. package/dist/transport/index.js +9 -0
  335. package/dist/transport/signals.d.ts +15 -0
  336. package/dist/transport/signals.js +123 -0
  337. package/dist/transport/signature.d.ts +7 -0
  338. package/dist/transport/signature.js +94 -0
  339. package/dist/transport/transport.d.ts +2 -0
  340. package/dist/transport/transport.js +202 -0
  341. package/dist/transport/types.d.ts +61 -0
  342. package/dist/transport/types.js +19 -0
  343. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  344. package/dist/usb-mode/catalog-schema.js +97 -0
  345. package/dist/usb-mode/catalog.d.ts +21 -0
  346. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  347. package/dist/usb-mode/certified-catalog.json +67 -0
  348. package/dist/usb-mode/index.d.ts +6 -0
  349. package/dist/usb-mode/index.js +16 -0
  350. package/dist/usb-mode/ingestion.d.ts +111 -0
  351. package/dist/usb-mode/ingestion.js +187 -0
  352. package/dist/usb-mode/promotion-review.d.ts +21 -0
  353. package/dist/usb-mode/promotion-review.js +87 -0
  354. package/dist/usb-mode/runtime-capability.d.ts +59 -0
  355. package/dist/usb-mode/runtime-capability.js +157 -0
  356. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  357. package/dist/usb-mode/usb-devices-parse.js +157 -0
  358. package/dist/ussd/calls.d.ts +32 -0
  359. package/dist/ussd/calls.js +96 -0
  360. package/dist/ussd/index.d.ts +5 -0
  361. package/dist/ussd/index.js +12 -0
  362. package/dist/ussd/mm-ussd.d.ts +37 -0
  363. package/dist/ussd/mm-ussd.js +205 -0
  364. package/dist/ussd/refusal.d.ts +53 -0
  365. package/dist/ussd/refusal.js +154 -0
  366. package/dist/ussd/registration.d.ts +20 -0
  367. package/dist/ussd/registration.js +101 -0
  368. package/dist/ussd/session.d.ts +106 -0
  369. package/dist/ussd/session.js +163 -0
  370. package/package.json +38 -4
  371. package/src/backend/at-lease.test.ts +0 -106
  372. package/src/backend/at-lease.ts +0 -158
  373. package/src/backend/cell-info.test.ts +0 -154
  374. package/src/backend/cell-info.ts +0 -160
  375. package/src/backend/device-classifier.test.ts +0 -168
  376. package/src/backend/device-classifier.ts +0 -248
  377. package/src/backend/enrichment.ts +0 -96
  378. package/src/backend/features.test.ts +0 -162
  379. package/src/backend/features.ts +0 -179
  380. package/src/backend/identity-ladder.test.ts +0 -117
  381. package/src/backend/identity-ladder.ts +0 -221
  382. package/src/backend/identity-registry.test.ts +0 -89
  383. package/src/backend/identity-registry.ts +0 -151
  384. package/src/backend/index.ts +0 -236
  385. package/src/backend/lifecycle-interlock.ts +0 -38
  386. package/src/backend/managed-objects.ts +0 -108
  387. package/src/backend/mapping.ts +0 -160
  388. package/src/backend/mm-backend.ts +0 -191
  389. package/src/backend/mm-mutations.ts +0 -228
  390. package/src/backend/modem-actor.test.ts +0 -95
  391. package/src/backend/modem-actor.ts +0 -112
  392. package/src/backend/nm-auto-apn.ts +0 -161
  393. package/src/backend/nm-gsm-fields.ts +0 -122
  394. package/src/backend/nmcli-nm-port.ts +0 -228
  395. package/src/backend/nmcli-runner.ts +0 -52
  396. package/src/backend/observer.ts +0 -297
  397. package/src/backend/power-contract.test.ts +0 -40
  398. package/src/backend/power-contract.ts +0 -83
  399. package/src/backend/recovery-attribution.test.ts +0 -102
  400. package/src/backend/recovery-attribution.ts +0 -86
  401. package/src/backend/recovery-budget.test.ts +0 -64
  402. package/src/backend/recovery-budget.ts +0 -84
  403. package/src/backend/recovery-ladder.test.ts +0 -257
  404. package/src/backend/recovery-ladder.ts +0 -249
  405. package/src/backend/router-ethernet.test.ts +0 -71
  406. package/src/backend/router-ethernet.ts +0 -90
  407. package/src/backend/row-store.ts +0 -105
  408. package/src/backend/signal-setup.ts +0 -112
  409. package/src/backend/sim-unlock.ts +0 -193
  410. package/src/backend/transition-preconditions.ts +0 -149
  411. package/src/backend/uhubctl-power-hook.test.ts +0 -274
  412. package/src/backend/uhubctl-power-hook.ts +0 -377
  413. package/src/backend/usage/accounting.test.ts +0 -147
  414. package/src/backend/usage/accounting.ts +0 -123
  415. package/src/backend/usage/billing-cycle.test.ts +0 -62
  416. package/src/backend/usage/billing-cycle.ts +0 -45
  417. package/src/backend/usage/index.ts +0 -60
  418. package/src/backend/usage/policy-store.test.ts +0 -164
  419. package/src/backend/usage/policy-store.ts +0 -216
  420. package/src/backend/usage/policy-write.test.ts +0 -198
  421. package/src/backend/usage/policy-write.ts +0 -207
  422. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  423. package/src/backend/usage/sampler.test.ts +0 -327
  424. package/src/backend/usage/sampler.ts +0 -282
  425. package/src/backend/usage/store.test.ts +0 -148
  426. package/src/backend/usage/store.ts +0 -177
  427. package/src/backend/usb-enumerator.test.ts +0 -87
  428. package/src/backend/usb-enumerator.ts +0 -181
  429. package/src/backend/usb-mode-transition.test.ts +0 -323
  430. package/src/backend/usb-mode-transition.ts +0 -253
  431. package/src/domain/brand.ts +0 -29
  432. package/src/domain/errors.ts +0 -77
  433. package/src/domain/guards.test.ts +0 -218
  434. package/src/domain/guards.ts +0 -144
  435. package/src/domain/identity.test.ts +0 -83
  436. package/src/domain/identity.ts +0 -165
  437. package/src/domain/index.ts +0 -12
  438. package/src/domain/snapshot.test.ts +0 -266
  439. package/src/domain/snapshot.ts +0 -120
  440. package/src/index.test.ts +0 -6
  441. package/src/index.ts +0 -15
  442. package/src/ports/README.md +0 -61
  443. package/src/ports/forbidden-surface.test.ts +0 -241
  444. package/src/ports/modem-manager.ts +0 -72
  445. package/src/ports/network-manager.ts +0 -87
  446. package/src/ports/ops.ts +0 -60
  447. package/src/ports/ops.type-test.ts +0 -39
  448. package/src/ports/receipts.test.ts +0 -153
  449. package/src/ports/reconcile.test.ts +0 -152
  450. package/src/ports/reconcile.ts +0 -338
  451. package/src/ports/router.ts +0 -29
  452. package/src/redact.test.ts +0 -82
  453. package/src/redact.ts +0 -73
  454. package/src/transport/README.md +0 -65
  455. package/src/transport/calls.ts +0 -113
  456. package/src/transport/characterization.test.ts +0 -260
  457. package/src/transport/codec.test.ts +0 -118
  458. package/src/transport/codec.ts +0 -240
  459. package/src/transport/conformance-python.test.ts +0 -152
  460. package/src/transport/conformance-same-lib.test.ts +0 -115
  461. package/src/transport/dbus-native-lib.d.ts +0 -19
  462. package/src/transport/dbus-native.ts +0 -85
  463. package/src/transport/index.ts +0 -30
  464. package/src/transport/no-library-leak.test.ts +0 -61
  465. package/src/transport/reliability.test.ts +0 -173
  466. package/src/transport/signals.ts +0 -150
  467. package/src/transport/signature.ts +0 -110
  468. package/src/transport/test-support/fake-service.ts +0 -168
  469. package/src/transport/test-support/independent-producer.py +0 -110
  470. package/src/transport/test-support/private-bus.ts +0 -66
  471. package/src/transport/transport.ts +0 -250
  472. package/src/transport/types.ts +0 -118
  473. package/src/usb-mode/catalog-schema.test.ts +0 -181
  474. package/src/usb-mode/catalog-schema.ts +0 -113
  475. package/src/usb-mode/certified-catalog.json +0 -67
  476. package/src/usb-mode/index.ts +0 -58
  477. package/src/usb-mode/ingestion.test.ts +0 -268
  478. package/src/usb-mode/ingestion.ts +0 -297
  479. package/src/usb-mode/promotion-review.ts +0 -117
  480. package/src/usb-mode/usb-devices-parse.ts +0 -196
@@ -0,0 +1,205 @@
1
+ const STRENGTH_POINTS = {
2
+ none: 0,
3
+ weak: 1,
4
+ moderate: 2,
5
+ strong: 3,
6
+ };
7
+ function scoreOf(points) {
8
+ if (points <= 0)
9
+ return 'unsupported';
10
+ if (points === 1)
11
+ return 'maybe';
12
+ if (points === 2)
13
+ return 'likely';
14
+ return 'supported';
15
+ }
16
+ function confidenceOf(points) {
17
+ return Math.min(1, points / 3);
18
+ }
19
+ function cacheSignature(request, registryRevision) {
20
+ return JSON.stringify({
21
+ registryRevision,
22
+ generation: request.generation,
23
+ transport: request.transport,
24
+ passiveFacts: request.passiveFacts,
25
+ composition: request.composition,
26
+ firmware: request.firmware ?? null,
27
+ });
28
+ }
29
+ function addCandidate(candidates, provider, profile, strength) {
30
+ const key = `${provider.id}\u0000${profile}`;
31
+ const existing = candidates.get(key);
32
+ if (existing === undefined) {
33
+ candidates.set(key, { provider, profile, points: STRENGTH_POINTS[strength] });
34
+ return;
35
+ }
36
+ existing.points += STRENGTH_POINTS[strength];
37
+ }
38
+ function unresolvedResult(status, request, points, evidence, conflicts) {
39
+ return {
40
+ status,
41
+ provider: null,
42
+ profile: null,
43
+ score: scoreOf(points),
44
+ confidence: confidenceOf(points),
45
+ evidence,
46
+ conflicts,
47
+ operations: null,
48
+ writable: false,
49
+ generation: request.generation,
50
+ physicalModemId: request.physicalModemId,
51
+ };
52
+ }
53
+ async function evaluate(registry, request) {
54
+ const evidence = [];
55
+ const conflicts = [];
56
+ const candidates = new Map();
57
+ const eligible = [];
58
+ for (const provider of registry.list()) {
59
+ const transportMatches = provider.eligibleTransports.includes(request.transport);
60
+ evidence.push({
61
+ provider: provider.id,
62
+ profile: null,
63
+ stage: 'transport-eligibility',
64
+ source: request.transport,
65
+ signal: transportMatches ? 'match' : 'mismatch',
66
+ strength: 'none',
67
+ detail: transportMatches ? 'eligible-transport' : 'ineligible-transport',
68
+ });
69
+ if (transportMatches)
70
+ eligible.push(provider);
71
+ }
72
+ for (const provider of eligible) {
73
+ for (const matcher of provider.passiveMatchers) {
74
+ const actual = request.passiveFacts
75
+ .filter((fact) => fact.kind === matcher.fact)
76
+ .map((fact) => fact.value);
77
+ const signal = actual.length === 0
78
+ ? 'unknown'
79
+ : actual.some((value) => matcher.expected.includes(value))
80
+ ? 'match'
81
+ : 'mismatch';
82
+ const item = {
83
+ provider: provider.id,
84
+ profile: matcher.profiles.length === 1 ? (matcher.profiles[0] ?? null) : null,
85
+ stage: 'passive-facts',
86
+ source: matcher.id,
87
+ signal,
88
+ strength: matcher.strength,
89
+ detail: signal === 'match' ? 'expected-fact-present' : 'expected-fact-not-proven',
90
+ };
91
+ evidence.push(item);
92
+ if (signal === 'mismatch' && matcher.required)
93
+ conflicts.push(item);
94
+ if (signal === 'match') {
95
+ for (const profile of matcher.profiles) {
96
+ addCandidate(candidates, provider, profile, matcher.strength);
97
+ }
98
+ }
99
+ }
100
+ }
101
+ for (const provider of eligible) {
102
+ for (const probe of provider.unauthenticatedProbes) {
103
+ const result = await probe.run(request);
104
+ const item = {
105
+ provider: provider.id,
106
+ profile: result.profiles.length === 1 ? (result.profiles[0] ?? null) : null,
107
+ stage: 'unauthenticated-fingerprint',
108
+ source: probe.id,
109
+ signal: result.signal,
110
+ strength: result.strength,
111
+ detail: result.detail,
112
+ };
113
+ evidence.push(item);
114
+ if (result.signal === 'mismatch')
115
+ conflicts.push(item);
116
+ if (result.signal === 'match') {
117
+ for (const profile of result.profiles) {
118
+ addCandidate(candidates, provider, profile, result.strength);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ const ranked = [...candidates.values()].sort((left, right) => right.points - left.points);
124
+ const top = ranked[0];
125
+ if (top === undefined)
126
+ return unresolvedResult('unsupported', request, 0, evidence, conflicts);
127
+ if (ranked[1]?.points === top.points) {
128
+ return unresolvedResult('ambiguous', request, top.points, evidence, conflicts);
129
+ }
130
+ if (top.provider.authenticatedProfile !== undefined) {
131
+ const auth = await top.provider.authenticatedProfile.authenticate(request, [top.profile]);
132
+ const matched = auth.status === 'matched' && auth.profile === top.profile;
133
+ const item = {
134
+ provider: top.provider.id,
135
+ profile: top.profile,
136
+ stage: 'authenticated-profile',
137
+ source: top.provider.authenticatedProfile.algorithm,
138
+ signal: matched ? 'match' : auth.status === 'unavailable' ? 'unknown' : 'mismatch',
139
+ strength: 'strong',
140
+ detail: auth.detail,
141
+ };
142
+ evidence.push(item);
143
+ if (!matched) {
144
+ conflicts.push(item);
145
+ return unresolvedResult('ambiguous', request, top.points, evidence, conflicts);
146
+ }
147
+ top.points += STRENGTH_POINTS.strong;
148
+ }
149
+ const context = { ...request, profile: top.profile };
150
+ for (const reader of top.provider.capabilityReaders) {
151
+ const result = await reader.read(context);
152
+ const item = {
153
+ provider: top.provider.id,
154
+ profile: top.profile,
155
+ stage: 'capability-read',
156
+ source: reader.id,
157
+ signal: result.signal,
158
+ strength: result.strength,
159
+ detail: result.detail,
160
+ };
161
+ evidence.push(item);
162
+ if (result.signal === 'match')
163
+ top.points += STRENGTH_POINTS[result.strength];
164
+ if (result.signal === 'mismatch')
165
+ conflicts.push(item);
166
+ }
167
+ if (scoreOf(top.points) !== 'supported') {
168
+ return unresolvedResult('ambiguous', request, top.points, evidence, conflicts);
169
+ }
170
+ const operations = top.provider.operations(top.profile);
171
+ return {
172
+ status: 'selected',
173
+ provider: top.provider.id,
174
+ profile: top.profile,
175
+ score: 'supported',
176
+ confidence: confidenceOf(top.points),
177
+ evidence,
178
+ conflicts,
179
+ operations,
180
+ writable: operations.access === 'read-write',
181
+ generation: request.generation,
182
+ physicalModemId: request.physicalModemId,
183
+ };
184
+ }
185
+ class GenerationScopedProviderMatcher {
186
+ registry;
187
+ /** Cache mutation is scoped by physical modem, generation, firmware and composition. */
188
+ #cache = new Map();
189
+ constructor(registry) {
190
+ this.registry = registry;
191
+ }
192
+ async match(request) {
193
+ const key = request.physicalModemId;
194
+ const signature = cacheSignature(request, this.registry.revision);
195
+ const cached = this.#cache.get(key);
196
+ if (cached?.signature === signature)
197
+ return cached.result;
198
+ const result = await evaluate(this.registry, request);
199
+ this.#cache.set(key, { signature, result });
200
+ return result;
201
+ }
202
+ }
203
+ export function createProviderMatcher(registry) {
204
+ return new GenerationScopedProviderMatcher(registry);
205
+ }
@@ -0,0 +1,7 @@
1
+ export declare const MODEM_MANAGER_REFUSAL_REASONS: readonly ['unauthorized', 'unsupported', 'wrong-state', 'busy', 'not-found', 'timed-out', 'disconnected', 'failed'];
2
+ export type ModemManagerRefusalReason = (typeof MODEM_MANAGER_REFUSAL_REASONS)[number];
3
+ export type ModemManagerRefusal = {
4
+ readonly reason: ModemManagerRefusalReason;
5
+ readonly retryable: boolean;
6
+ };
7
+ export declare function mapModemManagerError(error: unknown): ModemManagerRefusal;
@@ -0,0 +1,37 @@
1
+ import { DisconnectedError, TransportError } from '../../transport/index.js';
2
+ export const MODEM_MANAGER_REFUSAL_REASONS = [
3
+ 'unauthorized',
4
+ 'unsupported',
5
+ 'wrong-state',
6
+ 'busy',
7
+ 'not-found',
8
+ 'timed-out',
9
+ 'disconnected',
10
+ 'failed',
11
+ ];
12
+ function errorIdentity(error) {
13
+ if (!(error instanceof Error))
14
+ return String(error);
15
+ const dbusName = Reflect.get(error, 'dbusName');
16
+ return `${typeof dbusName === 'string' ? dbusName : error.name} ${error.message}`;
17
+ }
18
+ export function mapModemManagerError(error) {
19
+ if (error instanceof DisconnectedError)
20
+ return { reason: 'disconnected', retryable: true };
21
+ const identity = errorIdentity(error);
22
+ if (/Unauthorized|AccessDenied/i.test(identity))
23
+ return { reason: 'unauthorized', retryable: false };
24
+ if (/Unsupported|NotSupported/i.test(identity))
25
+ return { reason: 'unsupported', retryable: false };
26
+ if (/WrongState|InvalidState/i.test(identity))
27
+ return { reason: 'wrong-state', retryable: true };
28
+ if (/InProgress|Busy/i.test(identity))
29
+ return { reason: 'busy', retryable: true };
30
+ if (/NotFound|UnknownObject|UnknownModem/i.test(identity)) {
31
+ return { reason: 'not-found', retryable: false };
32
+ }
33
+ if (error instanceof TransportError && /timed out/i.test(error.message)) {
34
+ return { reason: 'timed-out', retryable: true };
35
+ }
36
+ return { reason: 'failed', retryable: false };
37
+ }
@@ -0,0 +1,10 @@
1
+ import type { MmDbusBackend } from '../../backend/index.js';
2
+ import type { ProviderExecutionContext } from '../contracts.js';
3
+ import { type RuntimeCompositionOperationDeps } from './runtime-composition-operation.js';
4
+ import type { ModemManagerProviderOperations, ModemManagerSnapshotResult } from './types.js';
5
+ export interface GenericOperationsDeps {
6
+ readonly backend: MmDbusBackend;
7
+ readonly runtimeComposition?: RuntimeCompositionOperationDeps;
8
+ readSnapshot(context: ProviderExecutionContext): Promise<ModemManagerSnapshotResult>;
9
+ }
10
+ export declare function createGenericOperations(deps: GenericOperationsDeps): Pick<ModemManagerProviderOperations, 'radio' | 'modes' | 'bands' | 'signal' | 'sim' | 'power' | 'usbComposition'>;
@@ -0,0 +1,209 @@
1
+ import { classifyOperationCompletion, defineOperationDescriptor, runtimePath, } from '../../domain/index.js';
2
+ import { bandWriteReadbackMatches, buildBandWriteDescriptor, buildModeWriteDescriptor, encodeModeSelection, matchAdvertisedCombination, sameSelection, selectionOf, } from '../../radio/index.js';
3
+ import { mapModemManagerError } from './errors.js';
4
+ import { createRuntimeCompositionOperation, } from './runtime-composition-operation.js';
5
+ const PROVIDER_ID = 'modemmanager';
6
+ const PROFILE = 'generic-mm';
7
+ function readDescriptor(id) {
8
+ return defineOperationDescriptor({
9
+ id,
10
+ support: { read: { supported: true }, write: { supported: false, reason: 'read-only' } },
11
+ authority: 'provider',
12
+ provider: PROVIDER_ID,
13
+ constraints: { kind: 'unconstrained' },
14
+ livePreconditions: ['modem-present', 'runtime-interface-present'],
15
+ availability: { state: 'available' },
16
+ mutationImpact: 'read',
17
+ retryClass: 'idempotent-read',
18
+ readback: { required: false },
19
+ rollback: { required: false },
20
+ journal: { required: false },
21
+ admission: { required: false },
22
+ evidence: { profiles: [PROFILE], firmware: [] },
23
+ confidence: 'high',
24
+ });
25
+ }
26
+ function writeDescriptor(id) {
27
+ return defineOperationDescriptor({
28
+ id,
29
+ support: { read: { supported: true }, write: { supported: true } },
30
+ authority: 'provider',
31
+ provider: PROVIDER_ID,
32
+ constraints: { kind: 'unconstrained' },
33
+ livePreconditions: ['modem-present', 'runtime-interface-present'],
34
+ availability: { state: 'available' },
35
+ mutationImpact: 'disruptive',
36
+ retryClass: 'never',
37
+ readback: { required: false },
38
+ rollback: { required: false },
39
+ journal: { required: true, reason: 'disruptive-radio-write' },
40
+ admission: { required: true, reason: 'provider-mutation' },
41
+ evidence: { profiles: [PROFILE], firmware: [] },
42
+ confidence: 'high',
43
+ });
44
+ }
45
+ function applied(context, value) {
46
+ return classifyOperationCompletion({
47
+ operation: 'read',
48
+ completionGeneration: context.generation,
49
+ currentGeneration: context.generation,
50
+ completion: { status: 'applied', value },
51
+ });
52
+ }
53
+ function refused(context, reason) {
54
+ return classifyOperationCompletion({
55
+ operation: 'read',
56
+ completionGeneration: context.generation,
57
+ currentGeneration: context.generation,
58
+ completion: { status: 'refused', reason },
59
+ });
60
+ }
61
+ function receiptReason(reason) {
62
+ const mapped = mapModemManagerError(new Error(reason));
63
+ return mapped.reason === 'failed' ? reason : mapped.reason;
64
+ }
65
+ export function createGenericOperations(deps) {
66
+ const readField = async (context, capability, select, reason) => {
67
+ const snapshot = await deps.readSnapshot(context);
68
+ if (!snapshot.ok)
69
+ return refused(context, snapshot.reason);
70
+ return snapshot.capabilities[capability]
71
+ ? applied(context, select(snapshot))
72
+ : refused(context, reason);
73
+ };
74
+ const readBands = async (context) => {
75
+ const snapshot = await deps.readSnapshot(context);
76
+ if (!snapshot.ok)
77
+ return refused(context, snapshot.reason);
78
+ if (!snapshot.capabilities.bandRead)
79
+ return refused(context, 'band-read-unsupported');
80
+ const result = await deps.backend.readBands(runtimePath(snapshot.modemPath));
81
+ return result.ok
82
+ ? applied(context, result.bands)
83
+ : refused(context, receiptReason(result.reason));
84
+ };
85
+ const radioDescriptor = writeDescriptor('modemmanager.radio-modes');
86
+ const radio = {
87
+ descriptor: radioDescriptor,
88
+ describe: () => Promise.resolve(radioDescriptor),
89
+ read: (context) => readField(context, 'modeRead', (snapshot) => snapshot.radio, 'mode-read-unsupported'),
90
+ write: async (context, input) => {
91
+ const snapshot = await deps.readSnapshot(context);
92
+ if (!snapshot.ok)
93
+ return refused(context, snapshot.reason);
94
+ if (!snapshot.capabilities.modeWrite)
95
+ return refused(context, 'mode-write-unsupported');
96
+ const receipt = await deps.backend.setRadioModes(runtimePath(snapshot.modemPath), input);
97
+ if (receipt.status !== 'applied')
98
+ return refused(context, receiptReason(receipt.reason));
99
+ return readField(context, 'modeRead', (next) => next.radio, 'mode-read-unsupported');
100
+ },
101
+ };
102
+ const readModeTruth = async (context) => readField(context, 'modeRead', (snapshot) => snapshot.radio.truth, 'mode-read-unsupported');
103
+ const modes = {
104
+ descriptor: buildModeWriteDescriptor({
105
+ provider: PROVIDER_ID,
106
+ profile: PROFILE,
107
+ truth: {
108
+ current: { state: 'not-reported' },
109
+ supported: { combinations: [], undecodable: [] },
110
+ },
111
+ writeSupported: true,
112
+ }),
113
+ describe: async (context) => {
114
+ const snapshot = await deps.readSnapshot(context);
115
+ return buildModeWriteDescriptor({
116
+ provider: PROVIDER_ID,
117
+ profile: PROFILE,
118
+ truth: snapshot.ok
119
+ ? snapshot.radio.truth
120
+ : {
121
+ current: { state: 'not-reported' },
122
+ supported: { combinations: [], undecodable: [] },
123
+ },
124
+ writeSupported: snapshot.ok && snapshot.capabilities.modeWrite,
125
+ });
126
+ },
127
+ read: readModeTruth,
128
+ write: async (context, selection) => {
129
+ const snapshot = await deps.readSnapshot(context);
130
+ if (!snapshot.ok)
131
+ return refused(context, snapshot.reason);
132
+ if (!snapshot.capabilities.modeWrite)
133
+ return refused(context, 'mode-write-unsupported');
134
+ // A selection the modem never advertised is refused outright — never rounded to
135
+ // the nearest advertised one. Substituting is how "prefer 4G" on a marginal cell
136
+ // silently becomes 5G-first, which `five-g-preference.ts` refuses for the same reason.
137
+ if (matchAdvertisedCombination(snapshot.radio.truth.supported, selection) === undefined) {
138
+ return refused(context, 'mode-combination-not-advertised');
139
+ }
140
+ const encoded = encodeModeSelection(selection);
141
+ if (!encoded.ok)
142
+ return refused(context, 'mode-name-unknown');
143
+ const receipt = await deps.backend.setModeCombination(runtimePath(snapshot.modemPath), encoded.allowedMask, encoded.preferredMask);
144
+ if (receipt.status !== 'applied')
145
+ return refused(context, receiptReason(receipt.reason));
146
+ const readback = await readModeTruth(context);
147
+ if (readback.status !== 'applied')
148
+ return readback;
149
+ // An accepted-but-ignored `SetCurrentModes` is indistinguishable from success at
150
+ // the call site, so the descriptor requires a readback and this enforces it.
151
+ return readback.value.current.state === 'reported' &&
152
+ sameSelection(selectionOf(readback.value.current.combination), selection)
153
+ ? readback
154
+ : refused(context, 'mode-write-readback-mismatch');
155
+ },
156
+ };
157
+ const bandDescriptorFor = (snapshot) => buildBandWriteDescriptor({
158
+ provider: PROVIDER_ID,
159
+ profile: PROFILE,
160
+ certification: snapshot.ok
161
+ ? snapshot.bandCertification
162
+ : {
163
+ required: true,
164
+ satisfied: false,
165
+ reason: 'band-certification-required',
166
+ offerable: [],
167
+ },
168
+ readSupported: snapshot.ok && snapshot.capabilities.bandRead,
169
+ });
170
+ const bands = {
171
+ descriptor: bandDescriptorFor({ ok: false, reason: 'not-found' }),
172
+ describe: async (context) => bandDescriptorFor(await deps.readSnapshot(context)),
173
+ read: readBands,
174
+ write: async (context, input) => {
175
+ const snapshot = await deps.readSnapshot(context);
176
+ if (!snapshot.ok)
177
+ return refused(context, snapshot.reason);
178
+ // The certification gate, second of two. `bandWrite` is already false without a
179
+ // catalog entry, and the descriptor already reads `refused` — but a band lock can
180
+ // take a working uplink off the air, so the call path refuses independently
181
+ // rather than trusting a consumer to have read the descriptor.
182
+ if (!snapshot.bandCertification.satisfied || !snapshot.capabilities.bandWrite)
183
+ return refused(context, 'band-write-certification-required');
184
+ const receipt = await deps.backend.setCurrentBands(runtimePath(snapshot.modemPath), input);
185
+ if (receipt.status !== 'applied')
186
+ return refused(context, receiptReason(receipt.reason));
187
+ const readback = await readBands(context);
188
+ if (readback.status !== 'applied')
189
+ return readback;
190
+ return bandWriteReadbackMatches(input, readback.value)
191
+ ? readback
192
+ : refused(context, 'band-write-readback-mismatch');
193
+ },
194
+ };
195
+ const signal = {
196
+ descriptor: readDescriptor('modemmanager.signal'),
197
+ read: (context) => readField(context, 'signalRead', (snapshot) => snapshot.signal, 'signal-read-unsupported'),
198
+ };
199
+ const sim = {
200
+ descriptor: readDescriptor('modemmanager.sim'),
201
+ read: (context) => readField(context, 'simRead', (snapshot) => snapshot.sim, 'sim-read-unsupported'),
202
+ };
203
+ const power = {
204
+ descriptor: readDescriptor('modemmanager.power'),
205
+ read: (context) => readField(context, 'powerRead', (snapshot) => snapshot.power, 'power-read-unsupported'),
206
+ };
207
+ const usbComposition = createRuntimeCompositionOperation(deps.runtimeComposition);
208
+ return { radio, modes, bands, signal, sim, power, usbComposition };
209
+ }
@@ -0,0 +1,4 @@
1
+ export * from './errors.js';
2
+ export * from './provider.js';
3
+ export * from './runtime-composition-operation.js';
4
+ export * from './types.js';
@@ -0,0 +1,4 @@
1
+ export * from './errors.js';
2
+ export * from './provider.js';
3
+ export * from './runtime-composition-operation.js';
4
+ export * from './types.js';
@@ -0,0 +1,21 @@
1
+ import type { MmLocation } from '../../backend/index.js';
2
+ import type { DbusTransport } from '../../transport/index.js';
3
+ import type { MmUssd } from '../../ussd/index.js';
4
+ import type { ProviderExecutionContext } from '../contracts.js';
5
+ import type { ModemManagerProviderOperations, ModemManagerSnapshotResult } from './types.js';
6
+ export interface ModuleOperationsOptions {
7
+ readonly transport: DbusTransport;
8
+ readonly destination: string;
9
+ readonly location: MmLocation;
10
+ readonly ussd: MmUssd;
11
+ readonly now: () => number;
12
+ readSnapshot(context: ProviderExecutionContext): Promise<ModemManagerSnapshotResult>;
13
+ }
14
+ type ModuleOperationSurface = Pick<ModemManagerProviderOperations, 'location' | 'sms' | 'ussd' | 'initiateUssd' | 'respondUssd' | 'cancelUssd' | 'fccCoverage'>;
15
+ export declare class ModemManagerModuleOperations {
16
+ #private;
17
+ readonly operations: ModuleOperationSurface;
18
+ constructor(options: ModuleOperationsOptions);
19
+ stop(): Promise<void>;
20
+ }
21
+ export {};
@@ -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,41 @@
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 { RuntimeCompositionOperationDeps } from './runtime-composition-operation.js';
8
+ import type { ModemManagerProviderLifecycle, ModemManagerProviderOperations, ModemManagerSnapshotResult } from './types.js';
9
+ export interface ModemManagerProviderOptions {
10
+ readonly transport: DbusTransport;
11
+ readonly destination?: string;
12
+ readonly quiesce?: QuiesceHook;
13
+ readonly now?: () => number;
14
+ /**
15
+ * The band-lock certification catalog. Defaults to the one shipped in this package,
16
+ * which is EMPTY — so a band write is refused on every device until a human-reviewed
17
+ * commit adds an entry carrying its bench transcript.
18
+ */
19
+ readonly bandCertificationCatalog?: BandCertificationCatalog;
20
+ /**
21
+ * The device's SKU, if the embedding process can resolve one.
22
+ *
23
+ * ModemManager's `Modem` interface carries `Model` and `Revision` but NO USB
24
+ * `vid:pid`, and `BandSku` is keyed on all three — so this package structurally
25
+ * cannot build one from the bus alone, and a partial match would certify a family
26
+ * no reviewer looked at. With no resolver injected there is no SKU, hence no entry,
27
+ * hence no band write: fail-closed, which is this module's whole stance.
28
+ */
29
+ readonly bandSku?: (context: ProviderExecutionContext) => BandSku | undefined;
30
+ readonly runtimeComposition?: RuntimeCompositionOperationDeps;
31
+ }
32
+ export declare class ModemManagerProvider implements ModemManagerProviderLifecycle {
33
+ #private;
34
+ readonly definition: ProviderDefinition<NormalizedModemObservation, ModemManagerProviderOperations>;
35
+ constructor(options: ModemManagerProviderOptions);
36
+ start(): ReturnType<MmDbusBackend['start']>;
37
+ observe(listener: ObservationListener): () => void;
38
+ stop(): Promise<void>;
39
+ readSnapshot(context: ProviderExecutionContext): Promise<ModemManagerSnapshotResult>;
40
+ }
41
+ export declare function createModemManagerProvider(options: ModemManagerProviderOptions): ModemManagerProvider;