@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,171 @@
1
+ import type { DeviceGeneration, EpochMillis } from '../../domain/index.js';
2
+ import type { AppliedConfiguration, DesiredProfile, NormalizationContext } from '../../observations/index.js';
3
+ import type { ConnectionId, DeviceIfname, GsmProfileInput, Receipt } from '../../ports/index.js';
4
+ /**
5
+ * NM's own device states (`NMDeviceState`), by name.
6
+ *
7
+ * The transitional members are kept rather than collapsed into "not activated",
8
+ * because a device in `prepare` carrying our connection is COMING UP, and reporting
9
+ * that as a lost bearer would turn every ordinary activation into a false alarm.
10
+ */
11
+ export declare const NM_DEVICE_STATES: readonly ['unknown', 'unmanaged', 'unavailable', 'disconnected', 'prepare', 'config', 'need-auth', 'ip-config', 'ip-check', 'secondaries', 'activated', 'deactivating', 'failed'];
12
+ export type NmDeviceState = (typeof NM_DEVICE_STATES)[number];
13
+ /**
14
+ * The bearer identity all three slots compare in.
15
+ *
16
+ * `username` and `password` are deliberately NOT members. A state slot is read,
17
+ * compared, and surfaced in divergence output; `gsm.password` is the one field in the
18
+ * profile the redaction module masks everywhere else, so putting it in a comparable
19
+ * value would re-open that hole through a side door. The credential lives in NM, is
20
+ * written through the port, and is never mirrored here.
21
+ */
22
+ export interface NmBearerBinding {
23
+ readonly connectionId: ConnectionId;
24
+ readonly deviceIfname: DeviceIfname;
25
+ readonly apn: string;
26
+ readonly autoConfig: boolean;
27
+ readonly homeOnly: boolean;
28
+ }
29
+ /**
30
+ * A bearer, or the positive absence of one.
31
+ *
32
+ * `unbound` exists so "NM answered, and it says nothing is in force on this device"
33
+ * is a VALUE rather than an unavailable observation. The distinction is load-bearing:
34
+ * an unavailable observation compares `indeterminate` against everything, which is
35
+ * right for "the device is gone" and wrong for "the device is here and idle" — the
36
+ * second is a definite divergence from a desired bearer, and an operator needs to see
37
+ * it as one.
38
+ */
39
+ export type NmBearerState = {
40
+ readonly kind: 'bound';
41
+ readonly binding: NmBearerBinding;
42
+ } | {
43
+ readonly kind: 'unbound';
44
+ readonly deviceIfname: DeviceIfname;
45
+ };
46
+ export declare function boundBearer(binding: NmBearerBinding): NmBearerState;
47
+ export declare function unboundBearer(deviceIfname: DeviceIfname): NmBearerState;
48
+ export declare function nmBearerBindingEquals(left: NmBearerBinding, right: NmBearerBinding): boolean;
49
+ /** The equality `describeStateDivergence` is driven with for NM state. */
50
+ export declare function nmBearerStateEquals(left: NmBearerState, right: NmBearerState): boolean;
51
+ /** The connection NM reports active on a device, with the settings it put in force. */
52
+ export interface NmObservedActiveConnection {
53
+ readonly connectionId: ConnectionId;
54
+ readonly apn: string;
55
+ readonly autoConfig: boolean;
56
+ readonly homeOnly: boolean;
57
+ }
58
+ /** One device exactly as NM reports it in a readout. */
59
+ export interface NmObservedDevice {
60
+ readonly ifname: DeviceIfname;
61
+ readonly state: NmDeviceState;
62
+ readonly activeConnection?: NmObservedActiveConnection;
63
+ }
64
+ /**
65
+ * ONE COMPLETE NM readout — an enumeration, never a delta.
66
+ *
67
+ * That is what makes re-enumeration detectable at all: a device missing from `devices`
68
+ * means the device is GONE, and a delta stream has no way to say that without a
69
+ * removal event nobody guarantees will arrive.
70
+ *
71
+ * `context` supplies the clock, the generation and the source epoch, exactly as the
72
+ * observation layer requires — this adapter has no clock of its own for observations
73
+ * and therefore cannot stamp a readout with a time it did not come from.
74
+ */
75
+ export interface NmObservationInput {
76
+ readonly context: NormalizationContext;
77
+ readonly devices: readonly NmObservedDevice[];
78
+ }
79
+ /** What an operator asked for: a saved profile, targeted at an exact device. */
80
+ export interface NmDesiredRequest {
81
+ readonly profile: GsmProfileInput;
82
+ readonly deviceIfname: DeviceIfname;
83
+ /** Opaque origin label (an RPC caller, a policy engine). Never a credential. */
84
+ readonly requestedBy: string;
85
+ /** Update this existing profile instead of creating a new one. */
86
+ readonly connectionId?: ConnectionId;
87
+ }
88
+ export declare const NM_ADAPTER_REFUSAL_REASONS: readonly ['no-desired-profile', 'profile-absent', 'activation-failed', 'deactivation-failed', 'write-failed'];
89
+ export type NmAdapterRefusalReason = (typeof NM_ADAPTER_REFUSAL_REASONS)[number];
90
+ export type NmSaveResult = {
91
+ readonly ok: true;
92
+ readonly connectionId: ConnectionId;
93
+ readonly desired: DesiredProfile<NmBearerState>;
94
+ } | {
95
+ readonly ok: false;
96
+ readonly reason: NmAdapterRefusalReason;
97
+ readonly receipt: Receipt;
98
+ };
99
+ /** Applying a desired profile: the write either took, or it did not and says why. */
100
+ export type NmApplyResult = {
101
+ readonly ok: true;
102
+ readonly applied: AppliedConfiguration<NmBearerState>;
103
+ readonly receipt: Receipt;
104
+ } | {
105
+ readonly ok: false;
106
+ readonly reason: NmAdapterRefusalReason;
107
+ readonly receipt: Receipt;
108
+ };
109
+ export declare const NM_APPLIED_LOSS_REASONS: readonly [
110
+ /** The readout has no such device at all — a re-enumeration, or an unplug. */
111
+ 'interface-absent',
112
+ /** The device is present and carries no active connection. */
113
+ 'interface-detached',
114
+ /** A DIFFERENT connection is active on our device. */
115
+ 'connection-replaced',
116
+ /** NM reports the device itself failed. */
117
+ 'activation-failed'];
118
+ export type NmAppliedLossReason = (typeof NM_APPLIED_LOSS_REASONS)[number];
119
+ /**
120
+ * The applied bearer stopped being in force.
121
+ *
122
+ * `previous` is retained rather than discarded: a caller deciding whether to re-apply
123
+ * or to roll back needs to know what WAS in force, and the applied slot has just been
124
+ * cleared precisely because it no longer describes reality.
125
+ */
126
+ export interface NmAppliedLoss {
127
+ readonly connectionId: ConnectionId;
128
+ readonly deviceIfname: DeviceIfname;
129
+ readonly reason: NmAppliedLossReason;
130
+ readonly lostAt: EpochMillis;
131
+ readonly generation: DeviceGeneration;
132
+ readonly previous: AppliedConfiguration<NmBearerState>;
133
+ }
134
+ export type NmAppliedOutcome =
135
+ /** A desired profile is tracked, and nothing has been put into force for it yet. */
136
+ {
137
+ readonly status: 'unapplied';
138
+ } | {
139
+ readonly status: 'retained';
140
+ readonly applied: AppliedConfiguration<NmBearerState>;
141
+ } | {
142
+ readonly status: 'pending';
143
+ readonly applied: AppliedConfiguration<NmBearerState>;
144
+ readonly deviceState: NmDeviceState;
145
+ } | {
146
+ readonly status: 'lost';
147
+ readonly loss: NmAppliedLoss;
148
+ };
149
+ export interface NmConnectionOutcome {
150
+ readonly connectionId: ConnectionId;
151
+ readonly outcome: NmAppliedOutcome;
152
+ }
153
+ /**
154
+ * The result of folding one readout.
155
+ *
156
+ * A readout from a superseded generation is REFUSED rather than applied late: the
157
+ * generation fence exists so a reply about a previous enumeration cannot clear applied
158
+ * state that belongs to the current one.
159
+ */
160
+ export type NmObservationResult = {
161
+ readonly kind: 'refused';
162
+ readonly reason: 'superseded-generation';
163
+ readonly currentGeneration: DeviceGeneration;
164
+ } | {
165
+ readonly kind: 'accepted';
166
+ readonly generation: DeviceGeneration;
167
+ readonly observedAt: EpochMillis;
168
+ readonly outcomes: readonly NmConnectionOutcome[];
169
+ /** Just the losses, so the case that matters is not behind a filter. */
170
+ readonly losses: readonly NmAppliedLoss[];
171
+ };
@@ -0,0 +1,77 @@
1
+ // The saved-vs-applied vocabulary, in NetworkManager's own terms.
2
+ //
3
+ // NM is the sole writer of bearers, APN, auth, roaming, autoconnect and activation
4
+ // (`ports/README.md` ownership matrix), and it is also the stack that draws the
5
+ // distinction this whole module is built on: a connection PROFILE is what was saved,
6
+ // an ACTIVE connection is what was actually put into force on a device, and the device
7
+ // itself reports what it is currently doing. `observations/state-separation.ts` models
8
+ // those three slots generically; this file gives them an NM-shaped payload.
9
+ //
10
+ // Radio, band, SIM and power operations are deliberately absent. Those belong to the
11
+ // ModemManager provider, and a second surface expressing them here would make two
12
+ // writers for one resource — the exact thing the ownership matrix exists to prevent.
13
+ // Nothing here carries a `PhysicalModemId` either: every slot is keyed by NM's own
14
+ // connection UUID, so this adapter can never become a second authority on which
15
+ // physical modem is which.
16
+ /**
17
+ * NM's own device states (`NMDeviceState`), by name.
18
+ *
19
+ * The transitional members are kept rather than collapsed into "not activated",
20
+ * because a device in `prepare` carrying our connection is COMING UP, and reporting
21
+ * that as a lost bearer would turn every ordinary activation into a false alarm.
22
+ */
23
+ export const NM_DEVICE_STATES = [
24
+ 'unknown',
25
+ 'unmanaged',
26
+ 'unavailable',
27
+ 'disconnected',
28
+ 'prepare',
29
+ 'config',
30
+ 'need-auth',
31
+ 'ip-config',
32
+ 'ip-check',
33
+ 'secondaries',
34
+ 'activated',
35
+ 'deactivating',
36
+ 'failed',
37
+ ];
38
+ export function boundBearer(binding) {
39
+ return { kind: 'bound', binding };
40
+ }
41
+ export function unboundBearer(deviceIfname) {
42
+ return { kind: 'unbound', deviceIfname };
43
+ }
44
+ export function nmBearerBindingEquals(left, right) {
45
+ return (left.connectionId === right.connectionId &&
46
+ left.deviceIfname === right.deviceIfname &&
47
+ left.apn === right.apn &&
48
+ left.autoConfig === right.autoConfig &&
49
+ left.homeOnly === right.homeOnly);
50
+ }
51
+ /** The equality `describeStateDivergence` is driven with for NM state. */
52
+ export function nmBearerStateEquals(left, right) {
53
+ if (left.kind === 'bound' && right.kind === 'bound') {
54
+ return nmBearerBindingEquals(left.binding, right.binding);
55
+ }
56
+ if (left.kind === 'unbound' && right.kind === 'unbound') {
57
+ return left.deviceIfname === right.deviceIfname;
58
+ }
59
+ return false;
60
+ }
61
+ export const NM_ADAPTER_REFUSAL_REASONS = [
62
+ 'no-desired-profile',
63
+ 'profile-absent',
64
+ 'activation-failed',
65
+ 'deactivation-failed',
66
+ 'write-failed',
67
+ ];
68
+ export const NM_APPLIED_LOSS_REASONS = [
69
+ /** The readout has no such device at all — a re-enumeration, or an unplug. */
70
+ 'interface-absent',
71
+ /** The device is present and carries no active connection. */
72
+ 'interface-detached',
73
+ /** A DIFFERENT connection is active on our device. */
74
+ 'connection-replaced',
75
+ /** NM reports the device itself failed. */
76
+ 'activation-failed',
77
+ ];
@@ -0,0 +1,13 @@
1
+ import { DomainError } from '../domain/index.js';
2
+ import type { ProviderDefinition, ProviderOperationsSurface } from './contracts.js';
3
+ export declare class ProviderRegistryError extends DomainError {
4
+ readonly reason: 'duplicate-provider' | 'empty-profile-version';
5
+ readonly name = "ProviderRegistryError";
6
+ constructor(reason: 'duplicate-provider' | 'empty-profile-version');
7
+ }
8
+ export interface ProviderRegistry {
9
+ readonly revision: number;
10
+ register<TObservation, TOperations extends ProviderOperationsSurface>(definition: ProviderDefinition<TObservation, TOperations>): void;
11
+ list(): readonly ProviderDefinition[];
12
+ }
13
+ export declare function createProviderRegistry(): ProviderRegistry;
@@ -0,0 +1,33 @@
1
+ import { DomainError } from '../domain/index.js';
2
+ export class ProviderRegistryError extends DomainError {
3
+ reason;
4
+ name = 'ProviderRegistryError';
5
+ constructor(reason) {
6
+ super(`provider registration refused: ${reason}`);
7
+ this.reason = reason;
8
+ }
9
+ }
10
+ class InMemoryProviderRegistry {
11
+ /** Startup registration is the registry's documented mutation boundary. */
12
+ #definitions = [];
13
+ #revision = 0;
14
+ get revision() {
15
+ return this.#revision;
16
+ }
17
+ register(definition) {
18
+ if (this.#definitions.some((candidate) => candidate.id === definition.id)) {
19
+ throw new ProviderRegistryError('duplicate-provider');
20
+ }
21
+ if (definition.profileVersion.trim().length === 0) {
22
+ throw new ProviderRegistryError('empty-profile-version');
23
+ }
24
+ this.#definitions.push(definition);
25
+ this.#revision += 1;
26
+ }
27
+ list() {
28
+ return [...this.#definitions];
29
+ }
30
+ }
31
+ export function createProviderRegistry() {
32
+ return new InMemoryProviderRegistry();
33
+ }
@@ -0,0 +1,6 @@
1
+ export * from './operations.js';
2
+ export * from './prohibitions.js';
3
+ export * from './provider.js';
4
+ export * from './qualcomm-evidence.js';
5
+ export * from './session.js';
6
+ export * from './transport.js';
@@ -0,0 +1,6 @@
1
+ export * from './operations.js';
2
+ export * from './prohibitions.js';
3
+ export * from './provider.js';
4
+ export * from './qualcomm-evidence.js';
5
+ export * from './session.js';
6
+ export * from './transport.js';
@@ -0,0 +1,41 @@
1
+ import { type OperationDescriptor, type OperationResult } from '../../domain/index.js';
2
+ import type { ProviderReadOperations } from '../contracts.js';
3
+ import { type UfiProhibitionClass, type UfiProhibitionReason } from './prohibitions.js';
4
+ export declare const UFI_PROFILE = "ufi-himi-read-only";
5
+ /** The reason every descriptor gives for its absent write half. One string, one meaning. */
6
+ export declare const UFI_READ_ONLY_REASON = "ufi-himi-provider-is-read-only";
7
+ export type UfiReadValue = Readonly<Record<string, unknown>>;
8
+ /**
9
+ * `ProviderReadOperations` is used verbatim rather than a local shape, because it has no
10
+ * `write` member to omit — the absence is structural, not a convention this file keeps.
11
+ */
12
+ export type UfiReadOperation = ProviderReadOperations<UfiReadValue>;
13
+ export declare const UFI_READ_OPERATION_IDS: readonly ['ufi.signal.read', 'ufi.details.read'];
14
+ export type UfiReadOperationId = (typeof UFI_READ_OPERATION_IDS)[number];
15
+ export declare function isUfiReadOperation(operationId: string): operationId is UfiReadOperationId;
16
+ export declare function ufiReadDescriptor(operationId: UfiReadOperationId): OperationDescriptor<never, UfiReadValue>;
17
+ export declare function ufiReadResult(generation: OperationResult<UfiReadValue>['generation'], value: UfiReadValue): OperationResult<UfiReadValue>;
18
+ export declare function ufiRefusedResult(generation: OperationResult<UfiReadValue>['generation'], reason: string): OperationResult<UfiReadValue>;
19
+ export type UfiOperationPlan = {
20
+ readonly status: 'read';
21
+ readonly operationId: UfiReadOperationId;
22
+ } | {
23
+ readonly status: 'refused';
24
+ readonly operationId: string;
25
+ readonly reason: UfiProhibitionReason | 'unknown-operation';
26
+ readonly prohibitionClass: UfiProhibitionClass | null;
27
+ /**
28
+ * A literal, and provable: this function takes no transport, holds no session,
29
+ * and returns synchronously — there is nothing here that could reach the device.
30
+ */
31
+ readonly transportContacted: false;
32
+ };
33
+ /**
34
+ * Resolve an operation id BEFORE anything is dialled.
35
+ *
36
+ * Prohibited ids are answered from the frozen table first, so a forbidden operation is
37
+ * never mistaken for a typo. An id that is neither prohibited nor a known read is
38
+ * `unknown-operation` — also refused, because a read-only provider's operation set is
39
+ * closed and "not in the set" is a complete answer.
40
+ */
41
+ export declare function planUfiOperation(operationId: string): UfiOperationPlan;
@@ -0,0 +1,66 @@
1
+ import { defineOperationDescriptor, } from '../../domain/index.js';
2
+ import { ufiProhibition, } from './prohibitions.js';
3
+ export const UFI_PROFILE = 'ufi-himi-read-only';
4
+ /** The reason every descriptor gives for its absent write half. One string, one meaning. */
5
+ export const UFI_READ_ONLY_REASON = 'ufi-himi-provider-is-read-only';
6
+ export const UFI_READ_OPERATION_IDS = ['ufi.signal.read', 'ufi.details.read'];
7
+ export function isUfiReadOperation(operationId) {
8
+ return UFI_READ_OPERATION_IDS.includes(operationId);
9
+ }
10
+ export function ufiReadDescriptor(operationId) {
11
+ return defineOperationDescriptor({
12
+ id: operationId,
13
+ support: {
14
+ read: { supported: true },
15
+ write: { supported: false, reason: UFI_READ_ONLY_REASON },
16
+ },
17
+ authority: 'provider',
18
+ provider: 'ufi-himi',
19
+ constraints: { kind: 'unconstrained' },
20
+ livePreconditions: ['ufi-himi-session'],
21
+ availability: { state: 'available' },
22
+ mutationImpact: 'read',
23
+ retryClass: 'idempotent-read',
24
+ readback: { required: false },
25
+ rollback: { required: false },
26
+ journal: { required: false },
27
+ admission: { required: false },
28
+ evidence: { profiles: [UFI_PROFILE], firmware: [] },
29
+ confidence: 'medium',
30
+ });
31
+ }
32
+ export function ufiReadResult(generation, value) {
33
+ return { status: 'applied', value, generation, requiresReconciliation: false };
34
+ }
35
+ export function ufiRefusedResult(generation, reason) {
36
+ return { status: 'refused', reason, generation, requiresReconciliation: false };
37
+ }
38
+ /**
39
+ * Resolve an operation id BEFORE anything is dialled.
40
+ *
41
+ * Prohibited ids are answered from the frozen table first, so a forbidden operation is
42
+ * never mistaken for a typo. An id that is neither prohibited nor a known read is
43
+ * `unknown-operation` — also refused, because a read-only provider's operation set is
44
+ * closed and "not in the set" is a complete answer.
45
+ */
46
+ export function planUfiOperation(operationId) {
47
+ const prohibition = ufiProhibition(operationId);
48
+ if (prohibition !== undefined) {
49
+ return {
50
+ status: 'refused',
51
+ operationId,
52
+ reason: prohibition.reason,
53
+ prohibitionClass: prohibition.class,
54
+ transportContacted: false,
55
+ };
56
+ }
57
+ if (isUfiReadOperation(operationId))
58
+ return { status: 'read', operationId };
59
+ return {
60
+ status: 'refused',
61
+ operationId,
62
+ reason: 'unknown-operation',
63
+ prohibitionClass: null,
64
+ transportContacted: false,
65
+ };
66
+ }
@@ -0,0 +1,62 @@
1
+ import { type OperationDescriptor } from '../../domain/index.js';
2
+ export type UfiProhibitionClass = 'device-integrity' | 'firmware' | 'recovery-automation' | 'diagnostic-channel' | 'transport-fallback';
3
+ export declare const UFI_PROHIBITED_OPERATIONS: {
4
+ readonly 'nv.write': {
5
+ readonly reason: 'nv-write-prohibited';
6
+ readonly class: 'device-integrity';
7
+ };
8
+ readonly 'efs.write': {
9
+ readonly reason: 'efs-write-prohibited';
10
+ readonly class: 'device-integrity';
11
+ };
12
+ readonly 'identity.write': {
13
+ readonly reason: 'identity-write-prohibited';
14
+ readonly class: 'device-integrity';
15
+ };
16
+ readonly 'calibration.write': {
17
+ readonly reason: 'calibration-write-prohibited';
18
+ readonly class: 'device-integrity';
19
+ };
20
+ readonly 'firmware.flash': {
21
+ readonly reason: 'firmware-flash-prohibited';
22
+ readonly class: 'firmware';
23
+ };
24
+ readonly 'edl.automation': {
25
+ readonly reason: 'edl-automation-prohibited';
26
+ readonly class: 'recovery-automation';
27
+ };
28
+ readonly 'driver.blind-retry': {
29
+ readonly reason: 'blind-driver-retry-prohibited';
30
+ readonly class: 'recovery-automation';
31
+ };
32
+ readonly 'interface.blind-retry': {
33
+ readonly reason: 'blind-interface-retry-prohibited';
34
+ readonly class: 'recovery-automation';
35
+ };
36
+ readonly 'diag.write': {
37
+ readonly reason: 'diag-write-prohibited';
38
+ readonly class: 'diagnostic-channel';
39
+ };
40
+ readonly 'diag.info-probe': {
41
+ readonly reason: 'diag-probe-is-bench-supervised-only';
42
+ readonly class: 'diagnostic-channel';
43
+ };
44
+ readonly 'shell.transport-fallback': {
45
+ readonly reason: 'shell-transport-fallback-prohibited';
46
+ readonly class: 'transport-fallback';
47
+ };
48
+ };
49
+ export type UfiProhibitedOperationId = keyof typeof UFI_PROHIBITED_OPERATIONS;
50
+ export type UfiProhibition = (typeof UFI_PROHIBITED_OPERATIONS)[UfiProhibitedOperationId];
51
+ export type UfiProhibitionReason = UfiProhibition['reason'];
52
+ export declare const UFI_PROHIBITED_OPERATION_IDS: readonly UfiProhibitedOperationId[];
53
+ export declare function isUfiProhibitedOperation(operationId: string): operationId is UfiProhibitedOperationId;
54
+ export declare function ufiProhibition(operationId: string): UfiProhibition | undefined;
55
+ /**
56
+ * An INERT descriptor, so the same refusal survives a trip through the operation engine.
57
+ *
58
+ * It declares read AND write unsupported and availability refused, and it constrains
59
+ * inputs to the empty set — three independent fences, each sufficient on its own. It
60
+ * carries no execute/readback/rollback function because none exists to carry.
61
+ */
62
+ export declare function ufiProhibitionDescriptor(operationId: UfiProhibitedOperationId): OperationDescriptor<unknown, never>;
@@ -0,0 +1,88 @@
1
+ // The Qualcomm/HIMI prohibition table.
2
+ //
3
+ // These operations have NO IMPLEMENTATION ANYWHERE in this provider — not a refused
4
+ // stub, not a disabled branch, not a private helper. The table below is inert DATA: it
5
+ // exists so a caller asking for one of these ids gets a NAMED refusal instead of an
6
+ // "unknown operation" shrug, and so the fence can be enumerated by a test rather than
7
+ // argued for in prose. Nothing here can perform anything.
8
+ //
9
+ // Why each is prohibited rather than merely gated:
10
+ //
11
+ // NV / EFS / identity / calibration writes — they rewrite the modem's own persistent
12
+ // storage. A bad write bricks the radio, forges an IMEI, or destroys the factory RF
13
+ // calibration, and none of the three is recoverable from this device's userspace.
14
+ // Identity writes are additionally illegal in most jurisdictions.
15
+ // Firmware flashing and EDL automation — an interrupted flash leaves a device that
16
+ // enumerates only in emergency-download mode, which needs physical access this
17
+ // controller by definition does not have on a deployed board.
18
+ // Blind driver / interface retries — re-binding a driver or cycling an interface
19
+ // "until it works" is how a transient enumeration fault becomes a reboot loop, and
20
+ // it destroys the evidence the next diagnosis needs.
21
+ // DIAG writes — the Qualcomm DIAG channel can reach every one of the above.
22
+ // The DIAG info probe — READ-only and legitimate, but bench-only and human-supervised
23
+ // (docs/UFI-DIAG-PROBE.md). It is not a production operation and never becomes one.
24
+ // Shell transport fallback — production never reaches this device over ADB, SSH,
25
+ // telnet or DIAG under any circumstance. The HIMI HTTP API is the only transport.
26
+ import { defineOperationDescriptor } from '../../domain/index.js';
27
+ export const UFI_PROHIBITED_OPERATIONS = {
28
+ 'nv.write': { reason: 'nv-write-prohibited', class: 'device-integrity' },
29
+ 'efs.write': { reason: 'efs-write-prohibited', class: 'device-integrity' },
30
+ 'identity.write': { reason: 'identity-write-prohibited', class: 'device-integrity' },
31
+ 'calibration.write': { reason: 'calibration-write-prohibited', class: 'device-integrity' },
32
+ 'firmware.flash': { reason: 'firmware-flash-prohibited', class: 'firmware' },
33
+ 'edl.automation': { reason: 'edl-automation-prohibited', class: 'recovery-automation' },
34
+ 'driver.blind-retry': { reason: 'blind-driver-retry-prohibited', class: 'recovery-automation' },
35
+ 'interface.blind-retry': {
36
+ reason: 'blind-interface-retry-prohibited',
37
+ class: 'recovery-automation',
38
+ },
39
+ 'diag.write': { reason: 'diag-write-prohibited', class: 'diagnostic-channel' },
40
+ 'diag.info-probe': {
41
+ reason: 'diag-probe-is-bench-supervised-only',
42
+ class: 'diagnostic-channel',
43
+ },
44
+ 'shell.transport-fallback': {
45
+ reason: 'shell-transport-fallback-prohibited',
46
+ class: 'transport-fallback',
47
+ },
48
+ };
49
+ export const UFI_PROHIBITED_OPERATION_IDS = Object.keys(UFI_PROHIBITED_OPERATIONS);
50
+ export function isUfiProhibitedOperation(operationId) {
51
+ return Object.hasOwn(UFI_PROHIBITED_OPERATIONS, operationId);
52
+ }
53
+ export function ufiProhibition(operationId) {
54
+ return isUfiProhibitedOperation(operationId) ? UFI_PROHIBITED_OPERATIONS[operationId] : undefined;
55
+ }
56
+ /**
57
+ * An INERT descriptor, so the same refusal survives a trip through the operation engine.
58
+ *
59
+ * It declares read AND write unsupported and availability refused, and it constrains
60
+ * inputs to the empty set — three independent fences, each sufficient on its own. It
61
+ * carries no execute/readback/rollback function because none exists to carry.
62
+ */
63
+ export function ufiProhibitionDescriptor(operationId) {
64
+ const { reason } = UFI_PROHIBITED_OPERATIONS[operationId];
65
+ return defineOperationDescriptor({
66
+ id: operationId,
67
+ support: {
68
+ read: { supported: false, reason },
69
+ write: { supported: false, reason },
70
+ },
71
+ authority: 'provider',
72
+ provider: 'ufi-himi',
73
+ constraints: { kind: 'allowed-values', values: [] },
74
+ livePreconditions: [],
75
+ availability: { state: 'refused', reason },
76
+ // `disruptive`, not `write`: every one of these rewrites persistent device state
77
+ // or drives a recovery mode. The engine treats any non-read impact as a write
78
+ // (queued behind the modem's actor), so the refusal path is identical.
79
+ mutationImpact: 'disruptive',
80
+ retryClass: 'never',
81
+ readback: { required: false },
82
+ rollback: { required: false },
83
+ journal: { required: false },
84
+ admission: { required: false },
85
+ evidence: { profiles: [], firmware: [] },
86
+ confidence: 'high',
87
+ });
88
+ }
@@ -0,0 +1,41 @@
1
+ import type { ObservationEnvelope } from '../../domain/index.js';
2
+ import type { NormalizedModemObservation } from '../../observations/index.js';
3
+ import type { CapabilityReader, ProviderDefinition, ProviderExecutionContext, ProviderMatchRequest, ProviderOperationsSurface } from '../contracts.js';
4
+ import { type UfiOperationPlan, type UfiReadOperation } from './operations.js';
5
+ import { type UfiProhibitedOperationId } from './prohibitions.js';
6
+ import { UFI_DIAG_PRODUCTION_ACCESS } from './qualcomm-evidence.js';
7
+ import { type UfiOptions, UfiSessionRuntime } from './session.js';
8
+ export type { UfiOptions } from './session.js';
9
+ export type UfiOperationsSurface = ProviderOperationsSurface & {
10
+ readonly access: 'read-only';
11
+ readonly reads: readonly UfiReadOperation[];
12
+ readonly prohibited: readonly UfiProhibitedOperationId[];
13
+ readonly diagAccess: typeof UFI_DIAG_PRODUCTION_ACCESS;
14
+ readonly plan: (operationId: string) => UfiOperationPlan;
15
+ };
16
+ export declare class UfiHimiProvider extends UfiSessionRuntime {
17
+ fingerprint(request: ProviderMatchRequest): Promise<{
18
+ signal: 'unknown';
19
+ strength: 'strong';
20
+ profiles: readonly string[];
21
+ detail: string;
22
+ } | {
23
+ signal: "match" | "unknown";
24
+ strength: 'strong';
25
+ profiles: string[];
26
+ detail: string;
27
+ }>;
28
+ capability(): CapabilityReader;
29
+ observe(context: ProviderExecutionContext): Promise<readonly ObservationEnvelope<NormalizedModemObservation>[]>;
30
+ operations(_profile: string): UfiOperationsSurface;
31
+ private readSignal;
32
+ private readDetails;
33
+ private usbEvidencePermitsProbe;
34
+ /**
35
+ * Reads are issued sequentially on ONE session. A `SessionOut` in any body drops the
36
+ * cached session so the NEXT generation may spend its own single login; it never
37
+ * re-authenticates inside this cycle.
38
+ */
39
+ private fetch;
40
+ }
41
+ export declare function createUfiHimiDefinition(options: UfiOptions): ProviderDefinition<NormalizedModemObservation, UfiOperationsSurface>;