@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
+ // The ModemManager USSD adapter — `Modem3gpp.Ussd` driven by the pure session
2
+ // machine in `./session`.
3
+ //
4
+ // Three properties are load-bearing and none of them is obvious from the D-Bus
5
+ // API alone:
6
+ //
7
+ // 1. **Every verb runs through the shared per-modem `ModemActor`.** A USSD
8
+ // session is a single network-side resource per subscriber, so two verbs
9
+ // interleaving on one modem is exactly the double-dialogue the network
10
+ // answers busy. The actor is keyed on the STABLE key, so the serialization
11
+ // survives a replug like every other disruptive op in this package.
12
+ //
13
+ // 2. **An unanswered session is closed at a bound, and the CANCEL is attempted.**
14
+ // A session nobody responds to stays open NETWORK-side; letting it expire in
15
+ // silence would leave the next `Initiate` failing busy for reasons the
16
+ // operator cannot see. The bound closes our machine and best-effort releases
17
+ // the network's — best-effort because a modem that did not answer the last
18
+ // call may not answer this one either, and a timeout must still terminate.
19
+ //
20
+ // 3. **A `closed` session resets the STORED state to idle, while the CALLER is
21
+ // told `closed`.** The machine is deliberately terminal so a finished session
22
+ // cannot be resurrected; the adapter's map is per-modem and long-lived, so it
23
+ // starts each new dialogue from a fresh machine.
24
+ //
25
+ // The carrier's text rides `ussdReply` and NOTHING here logs it. That field name
26
+ // is not cosmetic: `../redact` is key-based, so the name IS what guarantees the
27
+ // value is masked in every receipt, bundle, and log line it can reach.
28
+ import { MM_BUS_NAME } from '../backend/constants.js';
29
+ import { callCancel, callInitiate, callRespond, decodeRepliedState, readUssdState, } from './calls.js';
30
+ import { classifyUssdFailure } from './refusal.js';
31
+ import { readUssdRegistrationFacts } from './registration.js';
32
+ import { IDLE_SESSION, reduceUssdSession, } from './session.js';
33
+ /** A network round-trip. USSD legitimately takes tens of seconds. */
34
+ const DEFAULT_CALL_TIMEOUT_MS = 45_000;
35
+ /** How long a session may sit awaiting an operator response before it is closed. */
36
+ const DEFAULT_SESSION_IDLE_TIMEOUT_MS = 120_000;
37
+ const defaultScheduler = (delayMs, run) => {
38
+ const timer = setTimeout(run, delayMs);
39
+ timer.unref?.();
40
+ return {
41
+ cancel: () => {
42
+ clearTimeout(timer);
43
+ },
44
+ };
45
+ };
46
+ export class MmUssd {
47
+ #deps;
48
+ #destination;
49
+ #callTimeoutMs;
50
+ #idleTimeoutMs;
51
+ #scheduler;
52
+ #sessions = new Map();
53
+ #timers = new Map();
54
+ constructor(deps) {
55
+ this.#deps = deps;
56
+ this.#destination = deps.destination ?? MM_BUS_NAME;
57
+ this.#callTimeoutMs = deps.callTimeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;
58
+ this.#idleTimeoutMs = deps.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
59
+ this.#scheduler = deps.scheduler ?? defaultScheduler;
60
+ }
61
+ snapshot(modem) {
62
+ return this.#sessions.get(this.#deps.resolveStableKey(modem)) ?? IDLE_SESSION;
63
+ }
64
+ initiate(modem, ussdCommand) {
65
+ return this.#runVerb(modem, { kind: 'initiate' }, (target) => callInitiate(target, ussdCommand));
66
+ }
67
+ respond(modem, ussdResponse) {
68
+ return this.#runVerb(modem, { kind: 'respond' }, (target) => callRespond(target, ussdResponse));
69
+ }
70
+ cancel(modem) {
71
+ const key = this.#deps.resolveStableKey(modem);
72
+ return this.#deps.actor.run(key, async () => {
73
+ const gate = this.#gate(key, { kind: 'cancel' });
74
+ if (!gate.ok) {
75
+ return gate.result;
76
+ }
77
+ const target = this.#target(modem);
78
+ try {
79
+ await callCancel(target);
80
+ return this.#settle(key, { kind: 'cancelled' });
81
+ }
82
+ catch (error) {
83
+ return this.#fail(key, modem, error);
84
+ }
85
+ });
86
+ }
87
+ /** Drop every timer. A live session on the modem is NOT cancelled by this. */
88
+ stop() {
89
+ for (const timer of this.#timers.values()) {
90
+ timer.cancel();
91
+ }
92
+ this.#timers.clear();
93
+ }
94
+ async #runVerb(modem, event, dispatch) {
95
+ const key = this.#deps.resolveStableKey(modem);
96
+ return this.#deps.actor.run(key, async () => {
97
+ const gate = this.#gate(key, event);
98
+ if (!gate.ok) {
99
+ return gate.result;
100
+ }
101
+ const target = this.#target(modem);
102
+ try {
103
+ const ussdReply = await dispatch(target);
104
+ const sessionState = decodeRepliedState(await readUssdState(target));
105
+ const settled = this.#settle(key, { kind: 'replied', sessionState });
106
+ // A session the network kept open — whether or not it asked a
107
+ // question — is what the idle bound exists to release.
108
+ if (sessionState !== 'released') {
109
+ this.#armIdleTimeout(key, modem);
110
+ }
111
+ return { ...settled, ussdReply };
112
+ }
113
+ catch (error) {
114
+ return this.#fail(key, modem, error);
115
+ }
116
+ });
117
+ }
118
+ /**
119
+ * Apply the operator's verb to the machine. A refusal is returned WITHOUT
120
+ * touching the stored state or dialling the bus — a doomed verb must not
121
+ * disturb a live session.
122
+ */
123
+ #gate(key, event) {
124
+ const current = this.#sessions.get(key) ?? IDLE_SESSION;
125
+ const transition = reduceUssdSession(current, event);
126
+ if (!transition.ok) {
127
+ return {
128
+ ok: false,
129
+ result: { ok: false, snapshot: current, refusal: transition.refusal },
130
+ };
131
+ }
132
+ this.#store(key, transition.snapshot);
133
+ return { ok: true };
134
+ }
135
+ #settle(key, event) {
136
+ const current = this.#sessions.get(key) ?? IDLE_SESSION;
137
+ const transition = reduceUssdSession(current, event);
138
+ if (!transition.ok) {
139
+ return { ok: false, snapshot: current, refusal: transition.refusal };
140
+ }
141
+ this.#store(key, transition.snapshot);
142
+ const closedRefusal = transition.snapshot.refusal;
143
+ return {
144
+ ok: closedRefusal === undefined,
145
+ snapshot: transition.snapshot,
146
+ ...(closedRefusal === undefined ? {} : { refusal: closedRefusal }),
147
+ };
148
+ }
149
+ async #fail(key, modem, error) {
150
+ const registration = await readUssdRegistrationFacts(this.#deps.transport, this.#destination, modem);
151
+ return this.#settle(key, { kind: 'failed', reason: classifyUssdFailure(error, registration) });
152
+ }
153
+ /**
154
+ * A session reaching `closed` is REPORTED as closed and STORED as idle, so the
155
+ * next `initiate` starts from a fresh machine rather than the terminal one.
156
+ */
157
+ #store(key, snapshot) {
158
+ this.#clearTimer(key);
159
+ if (snapshot.state === 'closed') {
160
+ this.#sessions.delete(key);
161
+ }
162
+ else {
163
+ this.#sessions.set(key, snapshot);
164
+ }
165
+ this.#deps.onSessionChange?.(key, snapshot);
166
+ }
167
+ #armIdleTimeout(key, modem) {
168
+ this.#clearTimer(key);
169
+ this.#timers.set(key, this.#scheduler(this.#idleTimeoutMs, () => {
170
+ void this.#expire(key, modem);
171
+ }));
172
+ }
173
+ #clearTimer(key) {
174
+ this.#timers.get(key)?.cancel();
175
+ this.#timers.delete(key);
176
+ }
177
+ /**
178
+ * The bound elapsed. The machine closes `timed-out` FIRST — that outcome is
179
+ * the operator's answer whether or not the release lands — and the modem-side
180
+ * cancel is attempted afterwards, best-effort.
181
+ */
182
+ async #expire(key, modem) {
183
+ await this.#deps.actor.run(key, async () => {
184
+ if (!this.#sessions.has(key)) {
185
+ return;
186
+ }
187
+ this.#settle(key, { kind: 'timeout' });
188
+ try {
189
+ await callCancel(this.#target(modem));
190
+ }
191
+ catch {
192
+ // The modem that did not answer the dialogue may not answer this
193
+ // either; the session is already closed on our side.
194
+ }
195
+ });
196
+ }
197
+ #target(modem) {
198
+ return {
199
+ transport: this.#deps.transport,
200
+ destination: this.#destination,
201
+ modem,
202
+ timeoutMs: this.#callTimeoutMs,
203
+ };
204
+ }
205
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Every way a USSD verb can fail to do what the operator asked.
3
+ *
4
+ * unsupported — this modem exposes no USSD interface at all.
5
+ * lte-only-unsupported — the modem is registered PS-only (LTE/5G with no CS
6
+ * domain) and the network refused. NOT a device fault.
7
+ * carrier-rejected — the network refused for some other reason.
8
+ * not-registered — there is no network to carry the session.
9
+ * session-busy — a session is already open (locally or network-side).
10
+ * no-session — respond/cancel with nothing open.
11
+ * invalid-state — the verb is wrong for the state the session is in.
12
+ * timeout — the bounded wait elapsed with no answer.
13
+ * transport-failed — the bus call itself failed; the modem never answered.
14
+ */
15
+ export declare const USSD_REFUSAL_REASONS: readonly ['unsupported', 'lte-only-unsupported', 'carrier-rejected', 'not-registered', 'session-busy', 'no-session', 'invalid-state', 'timeout', 'transport-failed'];
16
+ export type UssdRefusalReason = (typeof USSD_REFUSAL_REASONS)[number];
17
+ /**
18
+ * What the modem is registered on, as far as anyone has looked.
19
+ *
20
+ * `csDomain` is the load-bearing field: `false` means the modem is attached with
21
+ * NO circuit-switched domain available (LTE/5G-SA without CSFB), which is the
22
+ * registration on which a plain USSD refusal is a carrier-policy statement rather
23
+ * than a device one. `undefined` means nobody read it, and is never treated as
24
+ * `false`.
25
+ */
26
+ export interface UssdRegistrationFacts {
27
+ readonly registered: boolean;
28
+ /** Is a circuit-switched domain available on this registration? */
29
+ readonly csDomain?: boolean;
30
+ /** MM access technologies currently in use, lowercased (`lte`, `5gnr`, …). */
31
+ readonly accessTechnologies?: readonly string[];
32
+ }
33
+ /**
34
+ * True when the modem's registration positively cannot carry a circuit-switched
35
+ * service. Requires evidence in BOTH directions: something must say the CS domain
36
+ * is absent, and every technology in use must be a packet-only one. A modem that
37
+ * reported no technologies at all answers `false` — an empty list is a statement
38
+ * about the read.
39
+ */
40
+ export declare function isPacketSwitchedOnly(facts: UssdRegistrationFacts): boolean;
41
+ /**
42
+ * Classify a failed USSD call. Pure, total, never throws.
43
+ *
44
+ * Order is deliberate: the D-Bus error NAME is the strongest signal and is read
45
+ * first; the message text is consulted only for the names MM overloads; anything
46
+ * unrecognised stays `transport-failed`, which is the honest answer for a failure
47
+ * whose origin cannot be attributed to the network.
48
+ *
49
+ * The PS-only promotion runs LAST and applies to exactly the two reasons that are
50
+ * ambiguous between a device limit and a carrier policy — a `not-registered` or a
51
+ * bus failure is neither, and is left alone.
52
+ */
53
+ export declare function classifyUssdFailure(error: unknown, registration?: UssdRegistrationFacts): UssdRefusalReason;
@@ -0,0 +1,154 @@
1
+ // Why a USSD verb did not succeed — one typed vocabulary, and the classifier that
2
+ // maps ModemManager's own failure surface onto it.
3
+ //
4
+ // The point of typing these is that every member names a DIFFERENT thing the
5
+ // operator can do, and the one this module exists for is the honest reporting of
6
+ // a carrier that will not carry USSD at all on the registration the modem has.
7
+ //
8
+ // THE LTE-ONLY CASE, stated plainly. USSD is a circuit-switched supplementary
9
+ // service. A modem registered PS-only — LTE or 5G-SA with no CS domain and no
10
+ // CSFB — can only carry it if the operator deploys USSI (USSD over IMS, 3GPP TS
11
+ // 24.390); many do not, and the modem/network then answers a generic
12
+ // unsupported/failed error that is indistinguishable, on its face, from "this
13
+ // modem has no USSD interface". Reporting that as a device limitation would send
14
+ // an operator hunting for a firmware fix for a network policy, so the classifier
15
+ // takes the modem's REGISTRATION alongside the error and separates the two.
16
+ //
17
+ // Nothing here guesses: `lte-only-unsupported` is claimed ONLY when the
18
+ // registration is positively known to be PS-only. An unknown registration keeps
19
+ // the generic reason, because "we did not look" is not evidence.
20
+ /**
21
+ * Every way a USSD verb can fail to do what the operator asked.
22
+ *
23
+ * unsupported — this modem exposes no USSD interface at all.
24
+ * lte-only-unsupported — the modem is registered PS-only (LTE/5G with no CS
25
+ * domain) and the network refused. NOT a device fault.
26
+ * carrier-rejected — the network refused for some other reason.
27
+ * not-registered — there is no network to carry the session.
28
+ * session-busy — a session is already open (locally or network-side).
29
+ * no-session — respond/cancel with nothing open.
30
+ * invalid-state — the verb is wrong for the state the session is in.
31
+ * timeout — the bounded wait elapsed with no answer.
32
+ * transport-failed — the bus call itself failed; the modem never answered.
33
+ */
34
+ export const USSD_REFUSAL_REASONS = [
35
+ 'unsupported',
36
+ 'lte-only-unsupported',
37
+ 'carrier-rejected',
38
+ 'not-registered',
39
+ 'session-busy',
40
+ 'no-session',
41
+ 'invalid-state',
42
+ 'timeout',
43
+ 'transport-failed',
44
+ ];
45
+ /** Access technologies that carry no circuit-switched domain of their own. */
46
+ const PACKET_ONLY_RATS = new Set([
47
+ 'lte',
48
+ '5gnr',
49
+ 'lte-cat-m',
50
+ 'lte-nb-iot',
51
+ ]);
52
+ /**
53
+ * True when the modem's registration positively cannot carry a circuit-switched
54
+ * service. Requires evidence in BOTH directions: something must say the CS domain
55
+ * is absent, and every technology in use must be a packet-only one. A modem that
56
+ * reported no technologies at all answers `false` — an empty list is a statement
57
+ * about the read.
58
+ */
59
+ export function isPacketSwitchedOnly(facts) {
60
+ if (!facts.registered) {
61
+ return false;
62
+ }
63
+ if (facts.csDomain !== false) {
64
+ return false;
65
+ }
66
+ const rats = facts.accessTechnologies;
67
+ if (rats === undefined || rats.length === 0) {
68
+ return false;
69
+ }
70
+ return rats.every((rat) => PACKET_ONLY_RATS.has(rat.toLowerCase()));
71
+ }
72
+ /**
73
+ * ModemManager D-Bus error names this classifier recognises, matched on the
74
+ * SUFFIX after the last dot so a future `...Error.Core.Unsupported` regrouping
75
+ * does not silently fall through to `transport-failed`.
76
+ */
77
+ const ERROR_SUFFIX_REASONS = new Map([
78
+ ['Unsupported', 'unsupported'],
79
+ ['NotSupported', 'unsupported'],
80
+ ['InProgress', 'session-busy'],
81
+ ['NoNetwork', 'not-registered'],
82
+ ['NotRegistered', 'not-registered'],
83
+ ['Timeout', 'timeout'],
84
+ ['Aborted', 'carrier-rejected'],
85
+ ['Failed', 'carrier-rejected'],
86
+ ]);
87
+ /**
88
+ * Message fragments that identify a refusal no error NAME distinguishes. MM
89
+ * folds several modem answers into `Core.Failed`, so the text is the only signal
90
+ * separating "the network said no" from "the bus call broke".
91
+ */
92
+ const MESSAGE_REASONS = [
93
+ [/ussd.*(?:not supported|unsupported)/i, 'unsupported'],
94
+ [/(?:session|operation) (?:already )?(?:active|in progress)/i, 'session-busy'],
95
+ [/no (?:active )?ussd session/i, 'no-session'],
96
+ [/not registered|no network/i, 'not-registered'],
97
+ [/timed? ?out/i, 'timeout'],
98
+ [/rejected|refused|denied|network error/i, 'carrier-rejected'],
99
+ ];
100
+ function errorName(error) {
101
+ if (typeof error !== 'object' || error === null) {
102
+ return undefined;
103
+ }
104
+ const name = error.dbusName;
105
+ if (typeof name === 'string' && name.includes('.')) {
106
+ return name;
107
+ }
108
+ const fallback = error.name;
109
+ return typeof fallback === 'string' && fallback.includes('.') ? fallback : undefined;
110
+ }
111
+ function errorMessage(error) {
112
+ if (error instanceof Error) {
113
+ return error.message;
114
+ }
115
+ if (typeof error === 'object' && error !== null) {
116
+ const message = error.message;
117
+ if (typeof message === 'string') {
118
+ return message;
119
+ }
120
+ }
121
+ return String(error);
122
+ }
123
+ /**
124
+ * Classify a failed USSD call. Pure, total, never throws.
125
+ *
126
+ * Order is deliberate: the D-Bus error NAME is the strongest signal and is read
127
+ * first; the message text is consulted only for the names MM overloads; anything
128
+ * unrecognised stays `transport-failed`, which is the honest answer for a failure
129
+ * whose origin cannot be attributed to the network.
130
+ *
131
+ * The PS-only promotion runs LAST and applies to exactly the two reasons that are
132
+ * ambiguous between a device limit and a carrier policy — a `not-registered` or a
133
+ * bus failure is neither, and is left alone.
134
+ */
135
+ export function classifyUssdFailure(error, registration = { registered: false }) {
136
+ const name = errorName(error);
137
+ const suffix = name?.slice(name.lastIndexOf('.') + 1);
138
+ const message = errorMessage(error);
139
+ let reason = suffix === undefined ? undefined : ERROR_SUFFIX_REASONS.get(suffix);
140
+ // `Core.Failed` is MM's catch-all, so its message is worth more than its name.
141
+ if (reason === undefined || reason === 'carrier-rejected') {
142
+ for (const [pattern, mapped] of MESSAGE_REASONS) {
143
+ if (pattern.test(message)) {
144
+ reason = mapped;
145
+ break;
146
+ }
147
+ }
148
+ }
149
+ if (reason === undefined) {
150
+ return 'transport-failed';
151
+ }
152
+ const ambiguous = reason === 'unsupported' || reason === 'carrier-rejected';
153
+ return ambiguous && isPacketSwitchedOnly(registration) ? 'lte-only-unsupported' : reason;
154
+ }
@@ -0,0 +1,20 @@
1
+ import { type DecodedManagedObjects } from '../backend/managed-objects.js';
2
+ import type { DbusTransport } from '../transport/index.js';
3
+ import type { UssdRegistrationFacts } from './refusal.js';
4
+ /** Decode `Modem.AccessTechnologies` into the technology names in use. */
5
+ export declare function decodeAccessTechnologies(mask: number): readonly string[];
6
+ /**
7
+ * Derive the registration facts from an already-fetched managed-objects tree.
8
+ *
9
+ * Pure, so the derivation is testable against a fixture tree without a bus — the
10
+ * `sim-unlock.ts` split between "read the tree" and "decide from the tree".
11
+ */
12
+ export declare function registrationFactsFromTree(tree: DecodedManagedObjects, modemPath: string): UssdRegistrationFacts;
13
+ /** The unread default — every field withheld, so nothing can be claimed from it. */
14
+ export declare const UNKNOWN_REGISTRATION: UssdRegistrationFacts;
15
+ /**
16
+ * Read the registration facts for one modem. Fail-soft: a tree we could not fetch
17
+ * yields {@link UNKNOWN_REGISTRATION}, which can only ever make the refusal LESS
18
+ * specific.
19
+ */
20
+ export declare function readUssdRegistrationFacts(transport: DbusTransport, destination: string, modemPath: string): Promise<UssdRegistrationFacts>;
@@ -0,0 +1,101 @@
1
+ // Reading the registration facts the USSD refusal classifier needs.
2
+ //
3
+ // ModemManager publishes NO "is a circuit-switched domain available" property, so
4
+ // the fact has to be DERIVED — and the derivation is worth stating, because it is
5
+ // the difference between telling an operator their modem cannot do USSD and
6
+ // telling them their carrier will not carry it on this registration:
7
+ //
8
+ // * `Modem.AccessTechnologies` is a bitmask. When every bit in use is a
9
+ // packet-only radio (LTE, 5G-NR, LTE-M, NB-IoT) the modem is not camped on a
10
+ // circuit-switched radio at all.
11
+ // * `Modem3gpp.RegistrationState` still overrides that, because CS FALLBACK is
12
+ // exactly the case where an LTE-camped modem CAN reach the CS domain. MM has
13
+ // two states that say so outright — `HOME_CSFB_NOT_PREFERRED` (9) and
14
+ // `ROAMING_CSFB_NOT_PREFERRED` (10) — and a modem in either of them is
15
+ // reported CS-capable regardless of its radio.
16
+ //
17
+ // Both reads are best-effort and NEVER throw: a fact nobody could read is left
18
+ // `undefined`, which the classifier treats as "we did not look" rather than as a
19
+ // negative. That asymmetry is the whole safety property — an unread registration
20
+ // can only ever produce the generic refusal, never the more specific claim.
21
+ import { MODEM_IFACE, MODEM3GPP_IFACE } from '../backend/constants.js';
22
+ import { fetchManagedObjects, findInterface, numberProp, } from '../backend/managed-objects.js';
23
+ /** `MMModemAccessTechnology` bits this module names. */
24
+ const ACCESS_TECHNOLOGY_BITS = [
25
+ [1 << 1, 'gsm'],
26
+ [1 << 2, 'gsm-compact'],
27
+ [1 << 3, 'gprs'],
28
+ [1 << 4, 'edge'],
29
+ [1 << 5, 'umts'],
30
+ [1 << 6, 'hsdpa'],
31
+ [1 << 7, 'hsupa'],
32
+ [1 << 8, 'hspa'],
33
+ [1 << 9, 'hspa-plus'],
34
+ [1 << 10, '1xrtt'],
35
+ [1 << 11, 'evdo0'],
36
+ [1 << 12, 'evdoa'],
37
+ [1 << 13, 'evdob'],
38
+ [1 << 14, 'lte'],
39
+ [1 << 15, '5gnr'],
40
+ [1 << 16, 'lte-cat-m'],
41
+ [1 << 17, 'lte-nb-iot'],
42
+ ];
43
+ /** `MMModem3gppRegistrationState` values that mean the modem is on a network. */
44
+ const REGISTERED_STATES = new Set([1, 5, 6, 7, 9, 10]);
45
+ /** …and the two that positively advertise a circuit-switched fallback. */
46
+ const CSFB_STATES = new Set([9, 10]);
47
+ /** Decode `Modem.AccessTechnologies` into the technology names in use. */
48
+ export function decodeAccessTechnologies(mask) {
49
+ const names = [];
50
+ for (const [bit, name] of ACCESS_TECHNOLOGY_BITS) {
51
+ if ((mask & bit) !== 0) {
52
+ names.push(name);
53
+ }
54
+ }
55
+ return names;
56
+ }
57
+ /**
58
+ * Derive the registration facts from an already-fetched managed-objects tree.
59
+ *
60
+ * Pure, so the derivation is testable against a fixture tree without a bus — the
61
+ * `sim-unlock.ts` split between "read the tree" and "decide from the tree".
62
+ */
63
+ export function registrationFactsFromTree(tree, modemPath) {
64
+ const modem = findInterface(tree, modemPath, MODEM_IFACE);
65
+ const threeGpp = findInterface(tree, modemPath, MODEM3GPP_IFACE);
66
+ const registrationState = numberProp(threeGpp, 'RegistrationState');
67
+ const accessMask = numberProp(modem, 'AccessTechnologies');
68
+ const registered = registrationState !== undefined && REGISTERED_STATES.has(registrationState);
69
+ const technologies = accessMask === undefined ? undefined : decodeAccessTechnologies(accessMask);
70
+ // A CSFB registration is CS-capable outright. Otherwise the domain is only
71
+ // declared ABSENT when the radios in use were actually read and are all
72
+ // packet-only; an unread mask leaves the field undefined on purpose.
73
+ let csDomain;
74
+ if (registrationState !== undefined && CSFB_STATES.has(registrationState)) {
75
+ csDomain = true;
76
+ }
77
+ else if (technologies !== undefined && technologies.length > 0) {
78
+ csDomain = technologies.some((rat) => rat !== 'lte' && rat !== '5gnr' && rat !== 'lte-cat-m' && rat !== 'lte-nb-iot');
79
+ }
80
+ return {
81
+ registered,
82
+ ...(csDomain === undefined ? {} : { csDomain }),
83
+ ...(technologies === undefined ? {} : { accessTechnologies: technologies }),
84
+ };
85
+ }
86
+ /** The unread default — every field withheld, so nothing can be claimed from it. */
87
+ export const UNKNOWN_REGISTRATION = { registered: false };
88
+ /**
89
+ * Read the registration facts for one modem. Fail-soft: a tree we could not fetch
90
+ * yields {@link UNKNOWN_REGISTRATION}, which can only ever make the refusal LESS
91
+ * specific.
92
+ */
93
+ export async function readUssdRegistrationFacts(transport, destination, modemPath) {
94
+ try {
95
+ const tree = await fetchManagedObjects(transport, destination);
96
+ return registrationFactsFromTree(tree, modemPath);
97
+ }
98
+ catch {
99
+ return UNKNOWN_REGISTRATION;
100
+ }
101
+ }
@@ -0,0 +1,106 @@
1
+ import type { UssdRefusalReason } from './refusal.js';
2
+ /**
3
+ * Session states.
4
+ *
5
+ * Three of them (`idle`, `active`, `awaiting-reply`) mirror MM's own
6
+ * `MMModem3gppUssdSessionState`; the rest are LOCAL in-flight states, because MM
7
+ * has no state for "we dispatched a call and the reply has not landed". Without
8
+ * them a second `initiate` racing the first would be judged against `idle` and
9
+ * allowed through, which is exactly the double-open the network answers busy.
10
+ */
11
+ export declare const USSD_SESSION_STATES: readonly [
12
+ /** No session. MM `IDLE`. */
13
+ 'idle',
14
+ /** `Initiate` dispatched, reply outstanding. Local. */
15
+ 'initiating',
16
+ /** Network answered and the session is open with nothing pending. MM `ACTIVE`. */
17
+ 'active',
18
+ /** Network asked a question; a `Respond` is required. MM `USER_RESPONSE`. */
19
+ 'awaiting-reply',
20
+ /** `Respond` dispatched, reply outstanding. Local. */
21
+ 'responding',
22
+ /** `Cancel` dispatched, confirmation outstanding. Local. */
23
+ 'cancelling',
24
+ /** Terminal for this session object. A new session starts from a new machine. */
25
+ 'closed'];
26
+ export type UssdSessionState = (typeof USSD_SESSION_STATES)[number];
27
+ /** How a session that reached `closed` got there. */
28
+ export declare const USSD_SESSION_OUTCOMES: readonly [
29
+ /** The network completed the dialogue and released the session. */
30
+ 'completed',
31
+ /** The operator cancelled it. */
32
+ 'cancelled',
33
+ /** No answer within the bound; the machine closed it locally. */
34
+ 'timed-out',
35
+ /** The network or the modem refused. `refusal` names which. */
36
+ 'failed'];
37
+ export type UssdSessionOutcome = (typeof USSD_SESSION_OUTCOMES)[number];
38
+ /** MM's post-call session state, decoded. */
39
+ export type UssdRepliedState = 'awaiting-reply' | 'active' | 'released';
40
+ export type UssdSessionEvent =
41
+ /** The operator asked to open a session. */
42
+ {
43
+ readonly kind: 'initiate';
44
+ }
45
+ /** The operator answered a network prompt. */
46
+ | {
47
+ readonly kind: 'respond';
48
+ }
49
+ /** The operator asked to close the session. */
50
+ | {
51
+ readonly kind: 'cancel';
52
+ }
53
+ /**
54
+ * The network answered an `Initiate`/`Respond`. `sessionState` is MM's own
55
+ * post-call `Modem3gpp.Ussd.State`, decoded: the network either wants an
56
+ * answer, is holding the session open with nothing pending, or released it.
57
+ */
58
+ | {
59
+ readonly kind: 'replied';
60
+ readonly sessionState: UssdRepliedState;
61
+ }
62
+ /** A `Cancel` was confirmed by the modem. */
63
+ | {
64
+ readonly kind: 'cancelled';
65
+ }
66
+ /** The network released the session without our asking (notification path). */
67
+ | {
68
+ readonly kind: 'network-released';
69
+ }
70
+ /** The bounded wait elapsed with no answer. */
71
+ | {
72
+ readonly kind: 'timeout';
73
+ }
74
+ /** The call failed. The reason is carried onto the terminal state verbatim. */
75
+ | {
76
+ readonly kind: 'failed';
77
+ readonly reason: UssdRefusalReason;
78
+ };
79
+ export interface UssdSessionSnapshot {
80
+ readonly state: UssdSessionState;
81
+ /** Present only at `closed`. */
82
+ readonly outcome?: UssdSessionOutcome;
83
+ /** Present only at `closed` with outcome `failed`. */
84
+ readonly refusal?: UssdRefusalReason;
85
+ }
86
+ export type UssdTransition = {
87
+ readonly ok: true;
88
+ readonly snapshot: UssdSessionSnapshot;
89
+ }
90
+ /** The verb is not legal in this state, and the machine did NOT move. */
91
+ | {
92
+ readonly ok: false;
93
+ readonly refusal: UssdRefusalReason;
94
+ };
95
+ export declare const IDLE_SESSION: UssdSessionSnapshot;
96
+ /**
97
+ * Apply one event. TOTAL: every (state, event) pair has an answer, and an answer
98
+ * is either a new snapshot or a typed refusal that leaves the machine untouched.
99
+ *
100
+ * A `closed` machine accepts NOTHING — not even another `cancel`. Re-opening a
101
+ * terminal session would hide the fact that the previous one ended, and the
102
+ * cost of a fresh machine is one object.
103
+ */
104
+ export declare function reduceUssdSession(snapshot: UssdSessionSnapshot, event: UssdSessionEvent): UssdTransition;
105
+ /** True while the session still holds a network dialogue open. */
106
+ export declare function isUssdSessionOpen(snapshot: UssdSessionSnapshot): boolean;