@ceralive/modem-control 0.2.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +317 -0
  2. package/dist/backend/at-lease.d.ts +57 -0
  3. package/dist/backend/at-lease.js +109 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +76 -0
  61. package/dist/backend/transition-preconditions.js +64 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +196 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +19 -0
  146. package/dist/index.js +26 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +47 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operations/contracts.d.ts +72 -0
  196. package/dist/operations/contracts.js +1 -0
  197. package/dist/operations/index.d.ts +1 -0
  198. package/dist/operations/index.js +1 -0
  199. package/dist/operations/operation-engine.d.ts +16 -0
  200. package/dist/operations/operation-engine.js +194 -0
  201. package/dist/ports/index.d.ts +12 -0
  202. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  203. package/dist/ports/location.d.ts +87 -0
  204. package/dist/ports/location.js +36 -0
  205. package/dist/ports/modem-manager.d.ts +89 -0
  206. package/dist/ports/modem-manager.js +9 -0
  207. package/dist/ports/mutation-admission.d.ts +27 -0
  208. package/dist/ports/mutation-admission.js +9 -0
  209. package/dist/ports/network-manager.d.ts +68 -0
  210. package/dist/ports/network-manager.js +13 -0
  211. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  212. package/dist/ports/observation.js +7 -0
  213. package/dist/ports/ops.d.ts +44 -0
  214. package/dist/ports/ops.js +16 -0
  215. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  216. package/dist/ports/receipts.js +9 -0
  217. package/dist/ports/reconcile.d.ts +33 -0
  218. package/dist/ports/reconcile.js +200 -0
  219. package/dist/ports/resource-ownership.d.ts +29 -0
  220. package/dist/ports/resource-ownership.js +1 -0
  221. package/dist/ports/router.d.ts +19 -0
  222. package/dist/ports/router.js +7 -0
  223. package/dist/ports/sms.d.ts +64 -0
  224. package/dist/ports/sms.js +24 -0
  225. package/dist/ports/uhubctl.d.ts +6 -0
  226. package/dist/ports/uhubctl.js +1 -0
  227. package/dist/providers/contracts.d.ts +124 -0
  228. package/dist/providers/contracts.js +10 -0
  229. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  230. package/dist/providers/huawei-hilink/index.js +2 -0
  231. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  232. package/dist/providers/huawei-hilink/operations.js +56 -0
  233. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  234. package/dist/providers/huawei-hilink/provider.js +76 -0
  235. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  236. package/dist/providers/huawei-hilink/runtime.js +171 -0
  237. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  238. package/dist/providers/huawei-hilink/session.js +120 -0
  239. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  240. package/dist/providers/huawei-hilink/transport.js +1 -0
  241. package/dist/providers/index.d.ts +8 -0
  242. package/dist/providers/index.js +8 -0
  243. package/dist/providers/matcher.d.ts +3 -0
  244. package/dist/providers/matcher.js +205 -0
  245. package/dist/providers/modem-manager/errors.d.ts +7 -0
  246. package/dist/providers/modem-manager/errors.js +37 -0
  247. package/dist/providers/modem-manager/generic-operations.d.ts +8 -0
  248. package/dist/providers/modem-manager/generic-operations.js +207 -0
  249. package/dist/providers/modem-manager/index.d.ts +3 -0
  250. package/dist/providers/modem-manager/index.js +3 -0
  251. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  252. package/dist/providers/modem-manager/module-operations.js +118 -0
  253. package/dist/providers/modem-manager/provider.d.ts +39 -0
  254. package/dist/providers/modem-manager/provider.js +152 -0
  255. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  256. package/dist/providers/modem-manager/snapshot.js +204 -0
  257. package/dist/providers/modem-manager/types.d.ts +135 -0
  258. package/dist/providers/modem-manager/types.js +1 -0
  259. package/dist/providers/network-manager/adapter.d.ts +71 -0
  260. package/dist/providers/network-manager/adapter.js +348 -0
  261. package/dist/providers/network-manager/index.d.ts +2 -0
  262. package/dist/providers/network-manager/index.js +2 -0
  263. package/dist/providers/network-manager/types.d.ts +163 -0
  264. package/dist/providers/network-manager/types.js +77 -0
  265. package/dist/providers/registry.d.ts +13 -0
  266. package/dist/providers/registry.js +33 -0
  267. package/dist/providers/ufi-himi/index.d.ts +6 -0
  268. package/dist/providers/ufi-himi/index.js +6 -0
  269. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  270. package/dist/providers/ufi-himi/operations.js +66 -0
  271. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  272. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  273. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  274. package/dist/providers/ufi-himi/provider.js +204 -0
  275. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  276. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  277. package/dist/providers/ufi-himi/session.d.ts +46 -0
  278. package/dist/providers/ufi-himi/session.js +92 -0
  279. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  280. package/dist/providers/ufi-himi/transport.js +25 -0
  281. package/dist/providers/zte-goform/index.d.ts +2 -0
  282. package/dist/providers/zte-goform/index.js +2 -0
  283. package/dist/providers/zte-goform/provider.d.ts +51 -0
  284. package/dist/providers/zte-goform/provider.js +101 -0
  285. package/dist/providers/zte-goform/session.d.ts +17 -0
  286. package/dist/providers/zte-goform/session.js +133 -0
  287. package/dist/providers/zte-goform/transport.d.ts +16 -0
  288. package/dist/providers/zte-goform/transport.js +1 -0
  289. package/dist/radio/band-truth.d.ts +50 -0
  290. package/dist/radio/band-truth.js +92 -0
  291. package/dist/radio/index.d.ts +3 -0
  292. package/dist/radio/index.js +10 -0
  293. package/dist/radio/mode-combinations.d.ts +78 -0
  294. package/dist/radio/mode-combinations.js +198 -0
  295. package/dist/radio/mode-truth.d.ts +67 -0
  296. package/dist/radio/mode-truth.js +112 -0
  297. package/dist/redact.d.ts +15 -0
  298. package/dist/redact.js +189 -0
  299. package/dist/safety/composition-root.d.ts +28 -0
  300. package/dist/safety/composition-root.js +65 -0
  301. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  302. package/dist/safety/flock-resource-ownership.js +151 -0
  303. package/dist/safety/index.d.ts +2 -0
  304. package/dist/safety/index.js +2 -0
  305. package/dist/sms/dbus-messaging.d.ts +17 -0
  306. package/dist/sms/dbus-messaging.js +185 -0
  307. package/dist/sms/inbox-store.d.ts +10 -0
  308. package/dist/sms/inbox-store.js +82 -0
  309. package/dist/sms/index.d.ts +4 -0
  310. package/dist/sms/index.js +10 -0
  311. package/dist/sms/mmcli-parse.d.ts +54 -0
  312. package/dist/sms/mmcli-parse.js +224 -0
  313. package/dist/sms/normalize.d.ts +42 -0
  314. package/dist/sms/normalize.js +95 -0
  315. package/dist/testing/domain-fakes.d.ts +58 -0
  316. package/dist/testing/domain-fakes.js +98 -0
  317. package/dist/testing/index.d.ts +2 -0
  318. package/dist/testing/index.js +17 -0
  319. package/dist/testing/provider-fakes.d.ts +45 -0
  320. package/dist/testing/provider-fakes.js +64 -0
  321. package/dist/transport/calls.d.ts +9 -0
  322. package/dist/transport/calls.js +88 -0
  323. package/dist/transport/codec.d.ts +3 -0
  324. package/dist/transport/codec.js +207 -0
  325. package/dist/transport/dbus-native.d.ts +57 -0
  326. package/dist/transport/dbus-native.js +17 -0
  327. package/dist/transport/errors.d.ts +21 -0
  328. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  329. package/dist/transport/index.d.ts +4 -0
  330. package/dist/transport/index.js +9 -0
  331. package/dist/transport/signals.d.ts +15 -0
  332. package/dist/transport/signals.js +123 -0
  333. package/dist/transport/signature.d.ts +7 -0
  334. package/dist/transport/signature.js +94 -0
  335. package/dist/transport/transport.d.ts +2 -0
  336. package/dist/transport/transport.js +202 -0
  337. package/dist/transport/types.d.ts +61 -0
  338. package/dist/transport/types.js +19 -0
  339. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  340. package/dist/usb-mode/catalog-schema.js +97 -0
  341. package/dist/usb-mode/catalog.d.ts +21 -0
  342. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  343. package/dist/usb-mode/certified-catalog.json +67 -0
  344. package/dist/usb-mode/index.d.ts +5 -0
  345. package/dist/usb-mode/index.js +15 -0
  346. package/dist/usb-mode/ingestion.d.ts +111 -0
  347. package/dist/usb-mode/ingestion.js +187 -0
  348. package/dist/usb-mode/promotion-review.d.ts +21 -0
  349. package/dist/usb-mode/promotion-review.js +87 -0
  350. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  351. package/dist/usb-mode/usb-devices-parse.js +157 -0
  352. package/dist/ussd/calls.d.ts +32 -0
  353. package/dist/ussd/calls.js +96 -0
  354. package/dist/ussd/index.d.ts +5 -0
  355. package/dist/ussd/index.js +12 -0
  356. package/dist/ussd/mm-ussd.d.ts +37 -0
  357. package/dist/ussd/mm-ussd.js +205 -0
  358. package/dist/ussd/refusal.d.ts +53 -0
  359. package/dist/ussd/refusal.js +154 -0
  360. package/dist/ussd/registration.d.ts +20 -0
  361. package/dist/ussd/registration.js +101 -0
  362. package/dist/ussd/session.d.ts +84 -0
  363. package/dist/ussd/session.js +163 -0
  364. package/package.json +38 -4
  365. package/src/backend/at-lease.test.ts +0 -106
  366. package/src/backend/at-lease.ts +0 -158
  367. package/src/backend/cell-info.test.ts +0 -154
  368. package/src/backend/cell-info.ts +0 -160
  369. package/src/backend/device-classifier.test.ts +0 -168
  370. package/src/backend/device-classifier.ts +0 -248
  371. package/src/backend/enrichment.ts +0 -96
  372. package/src/backend/features.test.ts +0 -162
  373. package/src/backend/features.ts +0 -179
  374. package/src/backend/identity-ladder.test.ts +0 -117
  375. package/src/backend/identity-ladder.ts +0 -221
  376. package/src/backend/identity-registry.test.ts +0 -89
  377. package/src/backend/identity-registry.ts +0 -151
  378. package/src/backend/index.ts +0 -221
  379. package/src/backend/lifecycle-interlock.ts +0 -38
  380. package/src/backend/managed-objects.ts +0 -108
  381. package/src/backend/mapping.ts +0 -160
  382. package/src/backend/mm-backend.ts +0 -191
  383. package/src/backend/mm-mutations.ts +0 -228
  384. package/src/backend/modem-actor.test.ts +0 -95
  385. package/src/backend/modem-actor.ts +0 -112
  386. package/src/backend/nm-auto-apn.ts +0 -161
  387. package/src/backend/nm-gsm-fields.ts +0 -122
  388. package/src/backend/nmcli-nm-port.ts +0 -228
  389. package/src/backend/nmcli-runner.ts +0 -52
  390. package/src/backend/observer.ts +0 -297
  391. package/src/backend/power-contract.test.ts +0 -40
  392. package/src/backend/power-contract.ts +0 -83
  393. package/src/backend/recovery-attribution.test.ts +0 -102
  394. package/src/backend/recovery-attribution.ts +0 -86
  395. package/src/backend/recovery-budget.test.ts +0 -64
  396. package/src/backend/recovery-budget.ts +0 -84
  397. package/src/backend/recovery-ladder.test.ts +0 -257
  398. package/src/backend/recovery-ladder.ts +0 -249
  399. package/src/backend/router-ethernet.test.ts +0 -71
  400. package/src/backend/router-ethernet.ts +0 -90
  401. package/src/backend/row-store.ts +0 -105
  402. package/src/backend/signal-setup.ts +0 -112
  403. package/src/backend/sim-unlock.ts +0 -193
  404. package/src/backend/transition-preconditions.ts +0 -149
  405. package/src/backend/usage/accounting.test.ts +0 -147
  406. package/src/backend/usage/accounting.ts +0 -123
  407. package/src/backend/usage/billing-cycle.test.ts +0 -62
  408. package/src/backend/usage/billing-cycle.ts +0 -45
  409. package/src/backend/usage/index.ts +0 -37
  410. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  411. package/src/backend/usage/sampler.test.ts +0 -219
  412. package/src/backend/usage/sampler.ts +0 -228
  413. package/src/backend/usage/store.test.ts +0 -148
  414. package/src/backend/usage/store.ts +0 -177
  415. package/src/backend/usb-enumerator.test.ts +0 -87
  416. package/src/backend/usb-enumerator.ts +0 -181
  417. package/src/backend/usb-mode-transition.test.ts +0 -323
  418. package/src/backend/usb-mode-transition.ts +0 -253
  419. package/src/domain/brand.ts +0 -29
  420. package/src/domain/errors.ts +0 -77
  421. package/src/domain/guards.test.ts +0 -218
  422. package/src/domain/guards.ts +0 -144
  423. package/src/domain/identity.test.ts +0 -83
  424. package/src/domain/identity.ts +0 -165
  425. package/src/domain/index.ts +0 -12
  426. package/src/domain/snapshot.test.ts +0 -266
  427. package/src/domain/snapshot.ts +0 -120
  428. package/src/index.test.ts +0 -6
  429. package/src/index.ts +0 -15
  430. package/src/ports/README.md +0 -61
  431. package/src/ports/forbidden-surface.test.ts +0 -241
  432. package/src/ports/modem-manager.ts +0 -72
  433. package/src/ports/network-manager.ts +0 -87
  434. package/src/ports/ops.ts +0 -60
  435. package/src/ports/ops.type-test.ts +0 -39
  436. package/src/ports/receipts.test.ts +0 -153
  437. package/src/ports/reconcile.test.ts +0 -152
  438. package/src/ports/reconcile.ts +0 -338
  439. package/src/ports/router.ts +0 -29
  440. package/src/redact.test.ts +0 -82
  441. package/src/redact.ts +0 -73
  442. package/src/transport/README.md +0 -65
  443. package/src/transport/calls.ts +0 -113
  444. package/src/transport/characterization.test.ts +0 -260
  445. package/src/transport/codec.test.ts +0 -118
  446. package/src/transport/codec.ts +0 -240
  447. package/src/transport/conformance-python.test.ts +0 -152
  448. package/src/transport/conformance-same-lib.test.ts +0 -115
  449. package/src/transport/dbus-native-lib.d.ts +0 -19
  450. package/src/transport/dbus-native.ts +0 -85
  451. package/src/transport/index.ts +0 -30
  452. package/src/transport/no-library-leak.test.ts +0 -61
  453. package/src/transport/reliability.test.ts +0 -173
  454. package/src/transport/signals.ts +0 -150
  455. package/src/transport/signature.ts +0 -110
  456. package/src/transport/test-support/fake-service.ts +0 -168
  457. package/src/transport/test-support/independent-producer.py +0 -110
  458. package/src/transport/test-support/private-bus.ts +0 -66
  459. package/src/transport/transport.ts +0 -250
  460. package/src/transport/types.ts +0 -118
  461. package/src/usb-mode/catalog-schema.test.ts +0 -181
  462. package/src/usb-mode/catalog-schema.ts +0 -113
  463. package/src/usb-mode/certified-catalog.json +0 -67
  464. package/src/usb-mode/index.ts +0 -27
@@ -0,0 +1,120 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { parseHilinkSession, parseHilinkUserState, parseHilinkXmlValue, } from '../../hardware/router-parsers.js';
3
+ import { HILINK_PATHS } from './provider.js';
4
+ function base64(value) {
5
+ return Buffer.from(value).toString('base64');
6
+ }
7
+ function derivePassword(profile, username, password, token) {
8
+ if (profile.passwordType === 3)
9
+ return base64(password);
10
+ const passwordHash = base64(createHash('sha256').update(password).digest('hex'));
11
+ const loginHash = createHash('sha256').update(`${username}${passwordHash}${token}`).digest('hex');
12
+ return base64(loginHash);
13
+ }
14
+ function escapeXml(value) {
15
+ return value
16
+ .replace(/&/g, '&')
17
+ .replace(/</g, '&lt;')
18
+ .replace(/>/g, '&gt;')
19
+ .replace(/"/g, '&quot;')
20
+ .replace(/'/g, '&apos;');
21
+ }
22
+ function loginDocument(profile, username, password, token) {
23
+ return `<?xml version="1.0" encoding="UTF-8"?><request><Username>${escapeXml(username)}</Username><Password>${derivePassword(profile, username, password, token)}</Password><password_type>${profile.passwordType}</password_type></request>`;
24
+ }
25
+ function responseHeader(response, name) {
26
+ const expected = name.toLowerCase();
27
+ return Object.entries(response.headers ?? {}).find(([key]) => key.toLowerCase() === expected)?.[1];
28
+ }
29
+ function loggedInSession(response, fallback) {
30
+ const cookie = responseHeader(response, 'set-cookie')?.split(';', 1)[0]?.trim() ?? fallback.cookie;
31
+ const tokenHeader = responseHeader(response, '__requestverificationtoken') ??
32
+ responseHeader(response, '__requestverificationtokenone');
33
+ const token = tokenHeader?.split('#', 1)[0]?.trim() ?? fallback.token;
34
+ return { cookie, token };
35
+ }
36
+ export class HilinkSessionRuntime {
37
+ options;
38
+ #authenticated = new Map();
39
+ #serial = new Map();
40
+ constructor(options) {
41
+ this.options = options;
42
+ }
43
+ async withDevice(context, run) {
44
+ const key = String(context.physicalModemId);
45
+ const prior = this.#serial.get(key) ?? Promise.resolve();
46
+ let release = () => { };
47
+ const current = new Promise((resolve) => {
48
+ release = resolve;
49
+ });
50
+ const chain = prior.then(() => current);
51
+ this.#serial.set(key, chain);
52
+ await prior;
53
+ try {
54
+ return await run();
55
+ }
56
+ finally {
57
+ release();
58
+ if (this.#serial.get(key) === chain)
59
+ this.#serial.delete(key);
60
+ }
61
+ }
62
+ sessionKey(context) {
63
+ return `${context.physicalModemId}:${context.generation}`;
64
+ }
65
+ cachedSession(context) {
66
+ return this.#authenticated.get(this.sessionKey(context));
67
+ }
68
+ async authenticate(context, profile, cache) {
69
+ const sessionResponse = await this.request('GET', HILINK_PATHS.session);
70
+ if (sessionResponse.status === 401 || sessionResponse.status === 403)
71
+ return { status: 'refused', reason: 'auth-expired' };
72
+ if (sessionResponse.status !== 200)
73
+ return { status: 'refused', reason: 'unreachable' };
74
+ const initial = parseHilinkSession(sessionResponse.body);
75
+ if (initial === undefined)
76
+ return { status: 'refused', reason: 'malformed' };
77
+ const stateResponse = await this.getResponse(HILINK_PATHS.loginState, initial);
78
+ if (this.authExpired(stateResponse))
79
+ return { status: 'refused', reason: 'auth-expired' };
80
+ const state = parseHilinkUserState(stateResponse.body);
81
+ if (state === undefined)
82
+ return { status: 'refused', reason: 'malformed' };
83
+ if (state.passwordType !== profile.passwordType)
84
+ return { status: 'refused', reason: 'profile-mismatch' };
85
+ const login = await this.postResponse(HILINK_PATHS.login, loginDocument(profile, this.options.credentials.username, this.options.credentials.password, initial.token), initial);
86
+ if (this.authExpired(login))
87
+ return { status: 'refused', reason: 'auth-expired' };
88
+ if (login.status !== 200 || !/<response>\s*OK\s*<\/response>/i.test(login.body))
89
+ return { status: 'refused', reason: 'http-failure' };
90
+ const session = loggedInSession(login, initial);
91
+ if (cache)
92
+ this.#authenticated.set(this.sessionKey(context), session);
93
+ return { status: 'ready', session };
94
+ }
95
+ authExpired(response) {
96
+ return (response.status === 401 ||
97
+ response.status === 403 ||
98
+ parseHilinkXmlValue(response.body, 'code') === '125002');
99
+ }
100
+ getResponse(path, session) {
101
+ return this.request('GET', path, undefined, [`Cookie: ${session.cookie}`]);
102
+ }
103
+ postResponse(path, body, session) {
104
+ return this.request('POST', path, body, [
105
+ `Cookie: ${session.cookie}`,
106
+ `__RequestVerificationToken: ${session.token}`,
107
+ 'Content-Type: application/xml',
108
+ ]);
109
+ }
110
+ request(method, path, body, headers = []) {
111
+ return this.options.transport.request({
112
+ method,
113
+ url: `${this.options.adminUrl}${path}`,
114
+ ...(body === undefined ? {} : { body }),
115
+ headers,
116
+ interfaceName: this.options.interfaceName,
117
+ redirect: 'error',
118
+ });
119
+ }
120
+ }
@@ -0,0 +1,19 @@
1
+ export type HilinkHttpRequest = {
2
+ readonly method: 'GET' | 'POST';
3
+ readonly url: string;
4
+ readonly body?: string;
5
+ readonly headers: readonly string[];
6
+ readonly interfaceName: string;
7
+ readonly redirect: 'error';
8
+ };
9
+ export type HilinkHttpResponse = {
10
+ readonly status: number;
11
+ readonly body: string;
12
+ readonly headers?: Readonly<Record<string, string>>;
13
+ };
14
+ export interface HilinkTransport {
15
+ request(request: HilinkHttpRequest): Promise<HilinkHttpResponse>;
16
+ }
17
+ export type HilinkReplayExchange = HilinkHttpRequest & {
18
+ readonly response: HilinkHttpResponse;
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export * from './contracts.js';
2
+ export * from './huawei-hilink/index.js';
3
+ export * from './matcher.js';
4
+ export * from './modem-manager/index.js';
5
+ export * from './network-manager/index.js';
6
+ export * from './registry.js';
7
+ export * from './ufi-himi/index.js';
8
+ export * from './zte-goform/index.js';
@@ -0,0 +1,8 @@
1
+ export * from './contracts.js';
2
+ export * from './huawei-hilink/index.js';
3
+ export * from './matcher.js';
4
+ export * from './modem-manager/index.js';
5
+ export * from './network-manager/index.js';
6
+ export * from './registry.js';
7
+ export * from './ufi-himi/index.js';
8
+ export * from './zte-goform/index.js';
@@ -0,0 +1,3 @@
1
+ import type { ProviderMatcher } from './contracts.js';
2
+ import type { ProviderRegistry } from './registry.js';
3
+ export declare function createProviderMatcher(registry: ProviderRegistry): ProviderMatcher;
@@ -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,8 @@
1
+ import type { MmDbusBackend } from '../../backend/index.js';
2
+ import type { ProviderExecutionContext } from '../contracts.js';
3
+ import type { ModemManagerProviderOperations, ModemManagerSnapshotResult } from './types.js';
4
+ export interface GenericOperationsDeps {
5
+ readonly backend: MmDbusBackend;
6
+ readSnapshot(context: ProviderExecutionContext): Promise<ModemManagerSnapshotResult>;
7
+ }
8
+ export declare function createGenericOperations(deps: GenericOperationsDeps): Pick<ModemManagerProviderOperations, 'radio' | 'modes' | 'bands' | 'signal' | 'sim' | 'power'>;
@@ -0,0 +1,207 @@
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
+ const PROVIDER_ID = 'modemmanager';
5
+ const PROFILE = 'generic-mm';
6
+ function readDescriptor(id) {
7
+ return defineOperationDescriptor({
8
+ id,
9
+ support: { read: { supported: true }, write: { supported: false, reason: 'read-only' } },
10
+ authority: 'provider',
11
+ provider: PROVIDER_ID,
12
+ constraints: { kind: 'unconstrained' },
13
+ livePreconditions: ['modem-present', 'runtime-interface-present'],
14
+ availability: { state: 'available' },
15
+ mutationImpact: 'read',
16
+ retryClass: 'idempotent-read',
17
+ readback: { required: false },
18
+ rollback: { required: false },
19
+ journal: { required: false },
20
+ admission: { required: false },
21
+ evidence: { profiles: [PROFILE], firmware: [] },
22
+ confidence: 'high',
23
+ });
24
+ }
25
+ function writeDescriptor(id) {
26
+ return defineOperationDescriptor({
27
+ id,
28
+ support: { read: { supported: true }, write: { supported: true } },
29
+ authority: 'provider',
30
+ provider: PROVIDER_ID,
31
+ constraints: { kind: 'unconstrained' },
32
+ livePreconditions: ['modem-present', 'runtime-interface-present'],
33
+ availability: { state: 'available' },
34
+ mutationImpact: 'disruptive',
35
+ retryClass: 'never',
36
+ readback: { required: false },
37
+ rollback: { required: false },
38
+ journal: { required: true, reason: 'disruptive-radio-write' },
39
+ admission: { required: true, reason: 'provider-mutation' },
40
+ evidence: { profiles: [PROFILE], firmware: [] },
41
+ confidence: 'high',
42
+ });
43
+ }
44
+ function applied(context, value) {
45
+ return classifyOperationCompletion({
46
+ operation: 'read',
47
+ completionGeneration: context.generation,
48
+ currentGeneration: context.generation,
49
+ completion: { status: 'applied', value },
50
+ });
51
+ }
52
+ function refused(context, reason) {
53
+ return classifyOperationCompletion({
54
+ operation: 'read',
55
+ completionGeneration: context.generation,
56
+ currentGeneration: context.generation,
57
+ completion: { status: 'refused', reason },
58
+ });
59
+ }
60
+ function receiptReason(reason) {
61
+ const mapped = mapModemManagerError(new Error(reason));
62
+ return mapped.reason === 'failed' ? reason : mapped.reason;
63
+ }
64
+ export function createGenericOperations(deps) {
65
+ const readField = async (context, capability, select, reason) => {
66
+ const snapshot = await deps.readSnapshot(context);
67
+ if (!snapshot.ok)
68
+ return refused(context, snapshot.reason);
69
+ return snapshot.capabilities[capability]
70
+ ? applied(context, select(snapshot))
71
+ : refused(context, reason);
72
+ };
73
+ const readBands = async (context) => {
74
+ const snapshot = await deps.readSnapshot(context);
75
+ if (!snapshot.ok)
76
+ return refused(context, snapshot.reason);
77
+ if (!snapshot.capabilities.bandRead)
78
+ return refused(context, 'band-read-unsupported');
79
+ const result = await deps.backend.readBands(runtimePath(snapshot.modemPath));
80
+ return result.ok
81
+ ? applied(context, result.bands)
82
+ : refused(context, receiptReason(result.reason));
83
+ };
84
+ const radioDescriptor = writeDescriptor('modemmanager.radio-modes');
85
+ const radio = {
86
+ descriptor: radioDescriptor,
87
+ describe: () => Promise.resolve(radioDescriptor),
88
+ read: (context) => readField(context, 'modeRead', (snapshot) => snapshot.radio, 'mode-read-unsupported'),
89
+ write: async (context, input) => {
90
+ const snapshot = await deps.readSnapshot(context);
91
+ if (!snapshot.ok)
92
+ return refused(context, snapshot.reason);
93
+ if (!snapshot.capabilities.modeWrite)
94
+ return refused(context, 'mode-write-unsupported');
95
+ const receipt = await deps.backend.setRadioModes(runtimePath(snapshot.modemPath), input);
96
+ if (receipt.status !== 'applied')
97
+ return refused(context, receiptReason(receipt.reason));
98
+ return readField(context, 'modeRead', (next) => next.radio, 'mode-read-unsupported');
99
+ },
100
+ };
101
+ const readModeTruth = async (context) => readField(context, 'modeRead', (snapshot) => snapshot.radio.truth, 'mode-read-unsupported');
102
+ const modes = {
103
+ descriptor: buildModeWriteDescriptor({
104
+ provider: PROVIDER_ID,
105
+ profile: PROFILE,
106
+ truth: {
107
+ current: { state: 'not-reported' },
108
+ supported: { combinations: [], undecodable: [] },
109
+ },
110
+ writeSupported: true,
111
+ }),
112
+ describe: async (context) => {
113
+ const snapshot = await deps.readSnapshot(context);
114
+ return buildModeWriteDescriptor({
115
+ provider: PROVIDER_ID,
116
+ profile: PROFILE,
117
+ truth: snapshot.ok
118
+ ? snapshot.radio.truth
119
+ : {
120
+ current: { state: 'not-reported' },
121
+ supported: { combinations: [], undecodable: [] },
122
+ },
123
+ writeSupported: snapshot.ok && snapshot.capabilities.modeWrite,
124
+ });
125
+ },
126
+ read: readModeTruth,
127
+ write: async (context, selection) => {
128
+ const snapshot = await deps.readSnapshot(context);
129
+ if (!snapshot.ok)
130
+ return refused(context, snapshot.reason);
131
+ if (!snapshot.capabilities.modeWrite)
132
+ return refused(context, 'mode-write-unsupported');
133
+ // A selection the modem never advertised is refused outright — never rounded to
134
+ // the nearest advertised one. Substituting is how "prefer 4G" on a marginal cell
135
+ // silently becomes 5G-first, which `five-g-preference.ts` refuses for the same reason.
136
+ if (matchAdvertisedCombination(snapshot.radio.truth.supported, selection) === undefined) {
137
+ return refused(context, 'mode-combination-not-advertised');
138
+ }
139
+ const encoded = encodeModeSelection(selection);
140
+ if (!encoded.ok)
141
+ return refused(context, 'mode-name-unknown');
142
+ const receipt = await deps.backend.setModeCombination(runtimePath(snapshot.modemPath), encoded.allowedMask, encoded.preferredMask);
143
+ if (receipt.status !== 'applied')
144
+ return refused(context, receiptReason(receipt.reason));
145
+ const readback = await readModeTruth(context);
146
+ if (readback.status !== 'applied')
147
+ return readback;
148
+ // An accepted-but-ignored `SetCurrentModes` is indistinguishable from success at
149
+ // the call site, so the descriptor requires a readback and this enforces it.
150
+ return readback.value.current.state === 'reported' &&
151
+ sameSelection(selectionOf(readback.value.current.combination), selection)
152
+ ? readback
153
+ : refused(context, 'mode-write-readback-mismatch');
154
+ },
155
+ };
156
+ const bandDescriptorFor = (snapshot) => buildBandWriteDescriptor({
157
+ provider: PROVIDER_ID,
158
+ profile: PROFILE,
159
+ certification: snapshot.ok
160
+ ? snapshot.bandCertification
161
+ : {
162
+ required: true,
163
+ satisfied: false,
164
+ reason: 'band-certification-required',
165
+ offerable: [],
166
+ },
167
+ readSupported: snapshot.ok && snapshot.capabilities.bandRead,
168
+ });
169
+ const bands = {
170
+ descriptor: bandDescriptorFor({ ok: false, reason: 'not-found' }),
171
+ describe: async (context) => bandDescriptorFor(await deps.readSnapshot(context)),
172
+ read: readBands,
173
+ write: async (context, input) => {
174
+ const snapshot = await deps.readSnapshot(context);
175
+ if (!snapshot.ok)
176
+ return refused(context, snapshot.reason);
177
+ // The certification gate, second of two. `bandWrite` is already false without a
178
+ // catalog entry, and the descriptor already reads `refused` — but a band lock can
179
+ // take a working uplink off the air, so the call path refuses independently
180
+ // rather than trusting a consumer to have read the descriptor.
181
+ if (!snapshot.bandCertification.satisfied || !snapshot.capabilities.bandWrite)
182
+ return refused(context, 'band-write-certification-required');
183
+ const receipt = await deps.backend.setCurrentBands(runtimePath(snapshot.modemPath), input);
184
+ if (receipt.status !== 'applied')
185
+ return refused(context, receiptReason(receipt.reason));
186
+ const readback = await readBands(context);
187
+ if (readback.status !== 'applied')
188
+ return readback;
189
+ return bandWriteReadbackMatches(input, readback.value)
190
+ ? readback
191
+ : refused(context, 'band-write-readback-mismatch');
192
+ },
193
+ };
194
+ const signal = {
195
+ descriptor: readDescriptor('modemmanager.signal'),
196
+ read: (context) => readField(context, 'signalRead', (snapshot) => snapshot.signal, 'signal-read-unsupported'),
197
+ };
198
+ const sim = {
199
+ descriptor: readDescriptor('modemmanager.sim'),
200
+ read: (context) => readField(context, 'simRead', (snapshot) => snapshot.sim, 'sim-read-unsupported'),
201
+ };
202
+ const power = {
203
+ descriptor: readDescriptor('modemmanager.power'),
204
+ read: (context) => readField(context, 'powerRead', (snapshot) => snapshot.power, 'power-read-unsupported'),
205
+ };
206
+ return { radio, modes, bands, signal, sim, power };
207
+ }
@@ -0,0 +1,3 @@
1
+ export * from './errors.js';
2
+ export * from './provider.js';
3
+ export * from './types.js';
@@ -0,0 +1,3 @@
1
+ export * from './errors.js';
2
+ export * from './provider.js';
3
+ 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 {};