@ceralive/modem-control 1.0.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 (474) 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 -236
  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/uhubctl-power-hook.test.ts +0 -274
  406. package/src/backend/uhubctl-power-hook.ts +0 -377
  407. package/src/backend/usage/accounting.test.ts +0 -147
  408. package/src/backend/usage/accounting.ts +0 -123
  409. package/src/backend/usage/billing-cycle.test.ts +0 -62
  410. package/src/backend/usage/billing-cycle.ts +0 -45
  411. package/src/backend/usage/index.ts +0 -60
  412. package/src/backend/usage/policy-store.test.ts +0 -164
  413. package/src/backend/usage/policy-store.ts +0 -216
  414. package/src/backend/usage/policy-write.test.ts +0 -198
  415. package/src/backend/usage/policy-write.ts +0 -207
  416. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  417. package/src/backend/usage/sampler.test.ts +0 -327
  418. package/src/backend/usage/sampler.ts +0 -282
  419. package/src/backend/usage/store.test.ts +0 -148
  420. package/src/backend/usage/store.ts +0 -177
  421. package/src/backend/usb-enumerator.test.ts +0 -87
  422. package/src/backend/usb-enumerator.ts +0 -181
  423. package/src/backend/usb-mode-transition.test.ts +0 -323
  424. package/src/backend/usb-mode-transition.ts +0 -253
  425. package/src/domain/brand.ts +0 -29
  426. package/src/domain/errors.ts +0 -77
  427. package/src/domain/guards.test.ts +0 -218
  428. package/src/domain/guards.ts +0 -144
  429. package/src/domain/identity.test.ts +0 -83
  430. package/src/domain/identity.ts +0 -165
  431. package/src/domain/index.ts +0 -12
  432. package/src/domain/snapshot.test.ts +0 -266
  433. package/src/domain/snapshot.ts +0 -120
  434. package/src/index.test.ts +0 -6
  435. package/src/index.ts +0 -15
  436. package/src/ports/README.md +0 -61
  437. package/src/ports/forbidden-surface.test.ts +0 -241
  438. package/src/ports/modem-manager.ts +0 -72
  439. package/src/ports/network-manager.ts +0 -87
  440. package/src/ports/ops.ts +0 -60
  441. package/src/ports/ops.type-test.ts +0 -39
  442. package/src/ports/receipts.test.ts +0 -153
  443. package/src/ports/reconcile.test.ts +0 -152
  444. package/src/ports/reconcile.ts +0 -338
  445. package/src/ports/router.ts +0 -29
  446. package/src/redact.test.ts +0 -82
  447. package/src/redact.ts +0 -73
  448. package/src/transport/README.md +0 -65
  449. package/src/transport/calls.ts +0 -113
  450. package/src/transport/characterization.test.ts +0 -260
  451. package/src/transport/codec.test.ts +0 -118
  452. package/src/transport/codec.ts +0 -240
  453. package/src/transport/conformance-python.test.ts +0 -152
  454. package/src/transport/conformance-same-lib.test.ts +0 -115
  455. package/src/transport/dbus-native-lib.d.ts +0 -19
  456. package/src/transport/dbus-native.ts +0 -85
  457. package/src/transport/index.ts +0 -30
  458. package/src/transport/no-library-leak.test.ts +0 -61
  459. package/src/transport/reliability.test.ts +0 -173
  460. package/src/transport/signals.ts +0 -150
  461. package/src/transport/signature.ts +0 -110
  462. package/src/transport/test-support/fake-service.ts +0 -168
  463. package/src/transport/test-support/independent-producer.py +0 -110
  464. package/src/transport/test-support/private-bus.ts +0 -66
  465. package/src/transport/transport.ts +0 -250
  466. package/src/transport/types.ts +0 -118
  467. package/src/usb-mode/catalog-schema.test.ts +0 -181
  468. package/src/usb-mode/catalog-schema.ts +0 -113
  469. package/src/usb-mode/certified-catalog.json +0 -67
  470. package/src/usb-mode/index.ts +0 -58
  471. package/src/usb-mode/ingestion.test.ts +0 -268
  472. package/src/usb-mode/ingestion.ts +0 -297
  473. package/src/usb-mode/promotion-review.ts +0 -117
  474. package/src/usb-mode/usb-devices-parse.ts +0 -196
@@ -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: "unknown" | "match";
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>;
@@ -0,0 +1,204 @@
1
+ // Qualcomm UFI / HIMI — a READ-ONLY provider, by construction rather than by policy.
2
+ //
3
+ // This provider normalizes the telemetry the pure parsers already own
4
+ // (`hardware/router-parsers.ts` → `observations/sources/ufi.ts`, migrated in todo 17).
5
+ // It adds a session and a transport around them and nothing else: there is no write
6
+ // descriptor, no write command in the transport vocabulary, and no operation id outside
7
+ // the closed read set that resolves to anything but a typed refusal.
8
+ //
9
+ // The Qualcomm safety model it encodes lives in two neighbouring modules —
10
+ // `qualcomm-evidence.ts` (what a USB id proves) and `prohibitions.ts` (what may never be
11
+ // attempted). Both are inert data; neither can act.
12
+ import { epochMillis, sourceEpoch, stableKeyFromPhysicalModemId } from '../../domain/index.js';
13
+ import { parseUfiDetails, parseUfiSignal } from '../../hardware/router-parsers.js';
14
+ import { normalizeUfiObservation } from '../../observations/sources/ufi.js';
15
+ import { planUfiOperation, UFI_PROFILE, ufiReadDescriptor, ufiReadResult, ufiRefusedResult, } from './operations.js';
16
+ import { UFI_PROHIBITED_OPERATION_IDS } from './prohibitions.js';
17
+ import { UFI_DIAG_PRODUCTION_ACCESS, UFI_MATCHED_USB_IDS } from './qualcomm-evidence.js';
18
+ import { parseUfiReply, UFI_SESSION_REFUSAL, UfiSessionRuntime } from './session.js';
19
+ import { UFI_API_PATH } from './transport.js';
20
+ export class UfiHimiProvider extends UfiSessionRuntime {
21
+ async fingerprint(request) {
22
+ // The HIMI fingerprint needs a SESSION to read anything, so this probe is the one
23
+ // place a "harmless unauthenticated probe" would spend the provider's single
24
+ // bounded login. On a device that enumerated a USB id and it is not a HIMI id,
25
+ // that login would be aimed at somebody else's dongle — a credential attempt
26
+ // against hardware this provider has positive evidence it does not own. An
27
+ // ABSENT usb fact is still probed (nobody enumerated one; that is not a denial).
28
+ if (!this.usbEvidencePermitsProbe(request)) {
29
+ return {
30
+ signal: 'unknown',
31
+ strength: 'strong',
32
+ profiles: [],
33
+ detail: 'usb-id-is-not-himi',
34
+ };
35
+ }
36
+ const bodies = await this.fetch(request, ['getallstatus']);
37
+ const reply = parseUfiReply(bodies?.getallstatus ?? '');
38
+ const matched = reply?.reply === 'ok' && reply.params !== undefined;
39
+ return {
40
+ signal: matched ? 'match' : 'unknown',
41
+ strength: 'strong',
42
+ profiles: matched ? [UFI_PROFILE] : [],
43
+ detail: matched ? 'himi-json-shape' : 'himi-json-not-proven',
44
+ };
45
+ }
46
+ capability() {
47
+ return {
48
+ id: 'ufi-himi-telemetry',
49
+ read: async (context) => {
50
+ const bodies = await this.fetch(context, ['getsysinfo']);
51
+ const reply = parseUfiReply(bodies?.getsysinfo ?? '');
52
+ const supported = reply?.reply === 'ok' && reply.params !== undefined;
53
+ return {
54
+ signal: supported ? 'match' : 'mismatch',
55
+ strength: 'strong',
56
+ detail: supported ? 'telemetry-reported' : 'telemetry-refused',
57
+ };
58
+ },
59
+ };
60
+ }
61
+ async observe(context) {
62
+ const bodies = await this.fetch(context, [
63
+ 'getsysinfo',
64
+ 'getoverview',
65
+ 'getallstatus',
66
+ 'getproduceinfo',
67
+ ]);
68
+ if (bodies === undefined)
69
+ return [];
70
+ const produceInfo = bodies.getproduceinfo;
71
+ return [
72
+ normalizeUfiObservation({
73
+ sysinfo: bodies.getsysinfo ?? '',
74
+ overview: bodies.getoverview ?? '',
75
+ status: bodies.getallstatus ?? '',
76
+ ...(produceInfo === undefined ? {} : { produceInfo }),
77
+ }, {
78
+ stableKey: stableKeyFromPhysicalModemId(context.physicalModemId),
79
+ generation: context.generation,
80
+ sourceEpoch: sourceEpoch(1),
81
+ observedAt: epochMillis(this.observedAt()),
82
+ }),
83
+ ];
84
+ }
85
+ operations(_profile) {
86
+ return {
87
+ access: 'read-only',
88
+ reads: [
89
+ {
90
+ descriptor: ufiReadDescriptor('ufi.signal.read'),
91
+ read: (context) => this.readSignal(context),
92
+ },
93
+ {
94
+ descriptor: ufiReadDescriptor('ufi.details.read'),
95
+ read: (context) => this.readDetails(context),
96
+ },
97
+ ],
98
+ prohibited: UFI_PROHIBITED_OPERATION_IDS,
99
+ diagAccess: UFI_DIAG_PRODUCTION_ACCESS,
100
+ plan: planUfiOperation,
101
+ };
102
+ }
103
+ async readSignal(context) {
104
+ const bodies = await this.fetch(context, ['getsysinfo', 'getoverview', 'getallstatus']);
105
+ if (bodies === undefined)
106
+ return ufiRefusedResult(context.generation, 'session-unavailable');
107
+ const value = parseUfiSignal({
108
+ sysinfo: bodies.getsysinfo ?? '',
109
+ overview: bodies.getoverview ?? '',
110
+ status: bodies.getallstatus ?? '',
111
+ });
112
+ return ufiReadResult(context.generation, value);
113
+ }
114
+ async readDetails(context) {
115
+ const bodies = await this.fetch(context, ['getoverview', 'getsysinfo', 'getproduceinfo']);
116
+ if (bodies === undefined)
117
+ return ufiRefusedResult(context.generation, 'session-unavailable');
118
+ const details = parseUfiDetails({
119
+ overview: bodies.getoverview ?? '',
120
+ sysinfo: bodies.getsysinfo ?? '',
121
+ produceInfo: bodies.getproduceinfo ?? '',
122
+ });
123
+ return details === undefined
124
+ ? ufiRefusedResult(context.generation, 'not-reported')
125
+ : ufiReadResult(context.generation, details);
126
+ }
127
+ usbEvidencePermitsProbe(request) {
128
+ const enumerated = request.passiveFacts.filter((fact) => fact.kind === 'usb');
129
+ return (enumerated.length === 0 ||
130
+ enumerated.some((fact) => UFI_MATCHED_USB_IDS.some((id) => id === fact.value)));
131
+ }
132
+ /**
133
+ * Reads are issued sequentially on ONE session. A `SessionOut` in any body drops the
134
+ * cached session so the NEXT generation may spend its own single login; it never
135
+ * re-authenticates inside this cycle.
136
+ */
137
+ async fetch(request, commands) {
138
+ const session = await this.session(request);
139
+ if (session === undefined)
140
+ return undefined;
141
+ const bodies = {};
142
+ for (const command of commands) {
143
+ const response = await this.read(command, session);
144
+ bodies[command] = response.status === 200 ? response.body : '';
145
+ }
146
+ const refused = Object.values(bodies).some((body) => parseUfiReply(body)?.reply === UFI_SESSION_REFUSAL);
147
+ if (refused)
148
+ this.forgetSession(request);
149
+ return bodies;
150
+ }
151
+ }
152
+ export function createUfiHimiDefinition(options) {
153
+ const runtime = new UfiHimiProvider(options);
154
+ return {
155
+ id: 'ufi-himi',
156
+ profileVersion: '1',
157
+ eligibleTransports: ['network'],
158
+ passiveMatchers: [
159
+ {
160
+ // ONE matcher over both ids. `9024` is the RNDIS+ADB composition and `9091` is
161
+ // a firmware-chosen product id; both identify a HIMI stick, and NEITHER is
162
+ // evidence of a DIAG channel (see qualcomm-evidence.ts).
163
+ id: 'usb-qualcomm-himi',
164
+ fact: 'usb',
165
+ expected: UFI_MATCHED_USB_IDS,
166
+ profiles: [UFI_PROFILE],
167
+ strength: 'strong',
168
+ required: true,
169
+ },
170
+ ],
171
+ unauthenticatedProbes: [
172
+ { id: 'ufi-himi-shape', run: (request) => runtime.fingerprint(request) },
173
+ ],
174
+ capabilityReaders: [runtime.capability()],
175
+ observe: (context) => runtime.observe(context),
176
+ operations: (profile) => runtime.operations(profile),
177
+ contractFixtures: [
178
+ {
179
+ profile: UFI_PROFILE,
180
+ request: {
181
+ method: 'POST',
182
+ path: UFI_API_PATH,
183
+ cmdid: 'login',
184
+ credentials: '[redacted]',
185
+ interfaceBound: true,
186
+ redirects: 'disabled',
187
+ },
188
+ response: { reply: 'ok', session: '[redacted]' },
189
+ },
190
+ {
191
+ profile: UFI_PROFILE,
192
+ request: {
193
+ method: 'POST',
194
+ path: UFI_API_PATH,
195
+ cmdid: 'getsysinfo',
196
+ authorization: '[redacted]',
197
+ interfaceBound: true,
198
+ redirects: 'disabled',
199
+ },
200
+ response: { reply: 'ok', params: '[verbatim-diagnostics]' },
201
+ },
202
+ ],
203
+ };
204
+ }
@@ -0,0 +1,32 @@
1
+ export declare const UFI_RNDIS_ADB_USB_ID = "05c6:9024";
2
+ export declare const UFI_FIRMWARE_SPECIFIC_USB_ID = "05c6:9091";
3
+ export type UfiUsbClaim = 'rndis-network' | 'adb-interface';
4
+ export declare const UFI_USB_EVIDENCE: {
5
+ readonly "05c6:9024": readonly ["rndis-network", "adb-interface"];
6
+ /** Deliberately empty: a firmware-chosen product id claims nothing by itself. */
7
+ readonly "05c6:9091": readonly [];
8
+ };
9
+ export declare const UFI_MATCHED_USB_IDS: readonly ["05c6:9024", "05c6:9091"];
10
+ export declare function ufiUsbClaims(usbId: string): readonly UfiUsbClaim[];
11
+ export type UfiUsbInterfaceDescriptor = {
12
+ readonly number: number;
13
+ readonly interfaceClass: number;
14
+ readonly interfaceSubClass: number;
15
+ readonly interfaceProtocol: number;
16
+ };
17
+ export type UfiDiagEvidence = {
18
+ readonly state: 'descriptor-confirmed';
19
+ readonly interfaceNumber: number;
20
+ } | {
21
+ readonly state: 'not-proven';
22
+ readonly reason: 'product-id-is-not-evidence' | 'no-diag-interface-descriptor';
23
+ };
24
+ export declare function classifyUfiDiagEvidence(input: {
25
+ readonly usbId: string;
26
+ readonly interfaces: readonly UfiUsbInterfaceDescriptor[];
27
+ }): UfiDiagEvidence;
28
+ /**
29
+ * Unconditional. A descriptor-confirmed DIAG channel raises what a SUPERVISED BENCH
30
+ * operator may attempt by hand; it never raises what this package may do on its own.
31
+ */
32
+ export declare const UFI_DIAG_PRODUCTION_ACCESS: "prohibited";
@@ -0,0 +1,51 @@
1
+ // What a Qualcomm USB id does and does not prove.
2
+ //
3
+ // `05c6:9024` is the composition the bench UFI sticks enumerate in: RNDIS networking
4
+ // plus an ADB interface. That is EVIDENCE OF A COMPOSITION, not a permission — the ADB
5
+ // interface being present is exactly why production must be explicit that it never uses
6
+ // it (see `shell.transport-fallback` in prohibitions.ts).
7
+ //
8
+ // `05c6:9091` is a FIRMWARE-SPECIFIC product id. It is routinely read as "DIAG is
9
+ // available", and that reading is wrong: `05c6` is Qualcomm's generic vendor id and the
10
+ // product id is chosen by whoever built the firmware image, so it says nothing about
11
+ // which interfaces the device actually exposes. Treating it as proof of DIAG is how a
12
+ // tool ends up opening a channel that is not there, or worse, one that is there and
13
+ // belongs to something else.
14
+ //
15
+ // The only thing that proves a DIAG channel is a DIAG INTERFACE DESCRIPTOR. And even a
16
+ // confirmed one buys nothing in production: `UFI_DIAG_PRODUCTION_ACCESS` is `prohibited`
17
+ // unconditionally, and the supervised read-only info probe is a bench runbook
18
+ // (docs/UFI-DIAG-PROBE.md), never an operation this package can perform.
19
+ export const UFI_RNDIS_ADB_USB_ID = '05c6:9024';
20
+ export const UFI_FIRMWARE_SPECIFIC_USB_ID = '05c6:9091';
21
+ export const UFI_USB_EVIDENCE = {
22
+ [UFI_RNDIS_ADB_USB_ID]: ['rndis-network', 'adb-interface'],
23
+ /** Deliberately empty: a firmware-chosen product id claims nothing by itself. */
24
+ [UFI_FIRMWARE_SPECIFIC_USB_ID]: [],
25
+ };
26
+ export const UFI_MATCHED_USB_IDS = [UFI_RNDIS_ADB_USB_ID, UFI_FIRMWARE_SPECIFIC_USB_ID];
27
+ export function ufiUsbClaims(usbId) {
28
+ return Object.hasOwn(UFI_USB_EVIDENCE, usbId)
29
+ ? UFI_USB_EVIDENCE[usbId]
30
+ : [];
31
+ }
32
+ /** Qualcomm's DIAG interface: vendor-specific class/subclass with protocol 0x30. */
33
+ const DIAG_INTERFACE_CLASS = 0xff;
34
+ const DIAG_INTERFACE_SUBCLASS = 0xff;
35
+ const DIAG_INTERFACE_PROTOCOL = 0x30;
36
+ export function classifyUfiDiagEvidence(input) {
37
+ const diag = input.interfaces.find((descriptor) => descriptor.interfaceClass === DIAG_INTERFACE_CLASS &&
38
+ descriptor.interfaceSubClass === DIAG_INTERFACE_SUBCLASS &&
39
+ descriptor.interfaceProtocol === DIAG_INTERFACE_PROTOCOL);
40
+ if (diag !== undefined) {
41
+ return { state: 'descriptor-confirmed', interfaceNumber: diag.number };
42
+ }
43
+ return input.interfaces.length === 0
44
+ ? { state: 'not-proven', reason: 'product-id-is-not-evidence' }
45
+ : { state: 'not-proven', reason: 'no-diag-interface-descriptor' };
46
+ }
47
+ /**
48
+ * Unconditional. A descriptor-confirmed DIAG channel raises what a SUPERVISED BENCH
49
+ * operator may attempt by hand; it never raises what this package may do on its own.
50
+ */
51
+ export const UFI_DIAG_PRODUCTION_ACCESS = 'prohibited';