@ceralive/modem-control 0.2.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +317 -0
  2. package/dist/backend/at-lease.d.ts +57 -0
  3. package/dist/backend/at-lease.js +109 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +76 -0
  61. package/dist/backend/transition-preconditions.js +64 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +196 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +19 -0
  146. package/dist/index.js +26 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +47 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operations/contracts.d.ts +72 -0
  196. package/dist/operations/contracts.js +1 -0
  197. package/dist/operations/index.d.ts +1 -0
  198. package/dist/operations/index.js +1 -0
  199. package/dist/operations/operation-engine.d.ts +16 -0
  200. package/dist/operations/operation-engine.js +194 -0
  201. package/dist/ports/index.d.ts +12 -0
  202. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  203. package/dist/ports/location.d.ts +87 -0
  204. package/dist/ports/location.js +36 -0
  205. package/dist/ports/modem-manager.d.ts +89 -0
  206. package/dist/ports/modem-manager.js +9 -0
  207. package/dist/ports/mutation-admission.d.ts +27 -0
  208. package/dist/ports/mutation-admission.js +9 -0
  209. package/dist/ports/network-manager.d.ts +68 -0
  210. package/dist/ports/network-manager.js +13 -0
  211. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  212. package/dist/ports/observation.js +7 -0
  213. package/dist/ports/ops.d.ts +44 -0
  214. package/dist/ports/ops.js +16 -0
  215. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  216. package/dist/ports/receipts.js +9 -0
  217. package/dist/ports/reconcile.d.ts +33 -0
  218. package/dist/ports/reconcile.js +200 -0
  219. package/dist/ports/resource-ownership.d.ts +29 -0
  220. package/dist/ports/resource-ownership.js +1 -0
  221. package/dist/ports/router.d.ts +19 -0
  222. package/dist/ports/router.js +7 -0
  223. package/dist/ports/sms.d.ts +64 -0
  224. package/dist/ports/sms.js +24 -0
  225. package/dist/ports/uhubctl.d.ts +6 -0
  226. package/dist/ports/uhubctl.js +1 -0
  227. package/dist/providers/contracts.d.ts +124 -0
  228. package/dist/providers/contracts.js +10 -0
  229. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  230. package/dist/providers/huawei-hilink/index.js +2 -0
  231. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  232. package/dist/providers/huawei-hilink/operations.js +56 -0
  233. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  234. package/dist/providers/huawei-hilink/provider.js +76 -0
  235. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  236. package/dist/providers/huawei-hilink/runtime.js +171 -0
  237. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  238. package/dist/providers/huawei-hilink/session.js +120 -0
  239. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  240. package/dist/providers/huawei-hilink/transport.js +1 -0
  241. package/dist/providers/index.d.ts +8 -0
  242. package/dist/providers/index.js +8 -0
  243. package/dist/providers/matcher.d.ts +3 -0
  244. package/dist/providers/matcher.js +205 -0
  245. package/dist/providers/modem-manager/errors.d.ts +7 -0
  246. package/dist/providers/modem-manager/errors.js +37 -0
  247. package/dist/providers/modem-manager/generic-operations.d.ts +8 -0
  248. package/dist/providers/modem-manager/generic-operations.js +207 -0
  249. package/dist/providers/modem-manager/index.d.ts +3 -0
  250. package/dist/providers/modem-manager/index.js +3 -0
  251. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  252. package/dist/providers/modem-manager/module-operations.js +118 -0
  253. package/dist/providers/modem-manager/provider.d.ts +39 -0
  254. package/dist/providers/modem-manager/provider.js +152 -0
  255. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  256. package/dist/providers/modem-manager/snapshot.js +204 -0
  257. package/dist/providers/modem-manager/types.d.ts +135 -0
  258. package/dist/providers/modem-manager/types.js +1 -0
  259. package/dist/providers/network-manager/adapter.d.ts +71 -0
  260. package/dist/providers/network-manager/adapter.js +348 -0
  261. package/dist/providers/network-manager/index.d.ts +2 -0
  262. package/dist/providers/network-manager/index.js +2 -0
  263. package/dist/providers/network-manager/types.d.ts +163 -0
  264. package/dist/providers/network-manager/types.js +77 -0
  265. package/dist/providers/registry.d.ts +13 -0
  266. package/dist/providers/registry.js +33 -0
  267. package/dist/providers/ufi-himi/index.d.ts +6 -0
  268. package/dist/providers/ufi-himi/index.js +6 -0
  269. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  270. package/dist/providers/ufi-himi/operations.js +66 -0
  271. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  272. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  273. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  274. package/dist/providers/ufi-himi/provider.js +204 -0
  275. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  276. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  277. package/dist/providers/ufi-himi/session.d.ts +46 -0
  278. package/dist/providers/ufi-himi/session.js +92 -0
  279. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  280. package/dist/providers/ufi-himi/transport.js +25 -0
  281. package/dist/providers/zte-goform/index.d.ts +2 -0
  282. package/dist/providers/zte-goform/index.js +2 -0
  283. package/dist/providers/zte-goform/provider.d.ts +51 -0
  284. package/dist/providers/zte-goform/provider.js +101 -0
  285. package/dist/providers/zte-goform/session.d.ts +17 -0
  286. package/dist/providers/zte-goform/session.js +133 -0
  287. package/dist/providers/zte-goform/transport.d.ts +16 -0
  288. package/dist/providers/zte-goform/transport.js +1 -0
  289. package/dist/radio/band-truth.d.ts +50 -0
  290. package/dist/radio/band-truth.js +92 -0
  291. package/dist/radio/index.d.ts +3 -0
  292. package/dist/radio/index.js +10 -0
  293. package/dist/radio/mode-combinations.d.ts +78 -0
  294. package/dist/radio/mode-combinations.js +198 -0
  295. package/dist/radio/mode-truth.d.ts +67 -0
  296. package/dist/radio/mode-truth.js +112 -0
  297. package/dist/redact.d.ts +15 -0
  298. package/dist/redact.js +189 -0
  299. package/dist/safety/composition-root.d.ts +28 -0
  300. package/dist/safety/composition-root.js +65 -0
  301. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  302. package/dist/safety/flock-resource-ownership.js +151 -0
  303. package/dist/safety/index.d.ts +2 -0
  304. package/dist/safety/index.js +2 -0
  305. package/dist/sms/dbus-messaging.d.ts +17 -0
  306. package/dist/sms/dbus-messaging.js +185 -0
  307. package/dist/sms/inbox-store.d.ts +10 -0
  308. package/dist/sms/inbox-store.js +82 -0
  309. package/dist/sms/index.d.ts +4 -0
  310. package/dist/sms/index.js +10 -0
  311. package/dist/sms/mmcli-parse.d.ts +54 -0
  312. package/dist/sms/mmcli-parse.js +224 -0
  313. package/dist/sms/normalize.d.ts +42 -0
  314. package/dist/sms/normalize.js +95 -0
  315. package/dist/testing/domain-fakes.d.ts +58 -0
  316. package/dist/testing/domain-fakes.js +98 -0
  317. package/dist/testing/index.d.ts +2 -0
  318. package/dist/testing/index.js +17 -0
  319. package/dist/testing/provider-fakes.d.ts +45 -0
  320. package/dist/testing/provider-fakes.js +64 -0
  321. package/dist/transport/calls.d.ts +9 -0
  322. package/dist/transport/calls.js +88 -0
  323. package/dist/transport/codec.d.ts +3 -0
  324. package/dist/transport/codec.js +207 -0
  325. package/dist/transport/dbus-native.d.ts +57 -0
  326. package/dist/transport/dbus-native.js +17 -0
  327. package/dist/transport/errors.d.ts +21 -0
  328. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  329. package/dist/transport/index.d.ts +4 -0
  330. package/dist/transport/index.js +9 -0
  331. package/dist/transport/signals.d.ts +15 -0
  332. package/dist/transport/signals.js +123 -0
  333. package/dist/transport/signature.d.ts +7 -0
  334. package/dist/transport/signature.js +94 -0
  335. package/dist/transport/transport.d.ts +2 -0
  336. package/dist/transport/transport.js +202 -0
  337. package/dist/transport/types.d.ts +61 -0
  338. package/dist/transport/types.js +19 -0
  339. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  340. package/dist/usb-mode/catalog-schema.js +97 -0
  341. package/dist/usb-mode/catalog.d.ts +21 -0
  342. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  343. package/dist/usb-mode/certified-catalog.json +67 -0
  344. package/dist/usb-mode/index.d.ts +5 -0
  345. package/dist/usb-mode/index.js +15 -0
  346. package/dist/usb-mode/ingestion.d.ts +111 -0
  347. package/dist/usb-mode/ingestion.js +187 -0
  348. package/dist/usb-mode/promotion-review.d.ts +21 -0
  349. package/dist/usb-mode/promotion-review.js +87 -0
  350. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  351. package/dist/usb-mode/usb-devices-parse.js +157 -0
  352. package/dist/ussd/calls.d.ts +32 -0
  353. package/dist/ussd/calls.js +96 -0
  354. package/dist/ussd/index.d.ts +5 -0
  355. package/dist/ussd/index.js +12 -0
  356. package/dist/ussd/mm-ussd.d.ts +37 -0
  357. package/dist/ussd/mm-ussd.js +205 -0
  358. package/dist/ussd/refusal.d.ts +53 -0
  359. package/dist/ussd/refusal.js +154 -0
  360. package/dist/ussd/registration.d.ts +20 -0
  361. package/dist/ussd/registration.js +101 -0
  362. package/dist/ussd/session.d.ts +84 -0
  363. package/dist/ussd/session.js +163 -0
  364. package/package.json +38 -4
  365. package/src/backend/at-lease.test.ts +0 -106
  366. package/src/backend/at-lease.ts +0 -158
  367. package/src/backend/cell-info.test.ts +0 -154
  368. package/src/backend/cell-info.ts +0 -160
  369. package/src/backend/device-classifier.test.ts +0 -168
  370. package/src/backend/device-classifier.ts +0 -248
  371. package/src/backend/enrichment.ts +0 -96
  372. package/src/backend/features.test.ts +0 -162
  373. package/src/backend/features.ts +0 -179
  374. package/src/backend/identity-ladder.test.ts +0 -117
  375. package/src/backend/identity-ladder.ts +0 -221
  376. package/src/backend/identity-registry.test.ts +0 -89
  377. package/src/backend/identity-registry.ts +0 -151
  378. package/src/backend/index.ts +0 -221
  379. package/src/backend/lifecycle-interlock.ts +0 -38
  380. package/src/backend/managed-objects.ts +0 -108
  381. package/src/backend/mapping.ts +0 -160
  382. package/src/backend/mm-backend.ts +0 -191
  383. package/src/backend/mm-mutations.ts +0 -228
  384. package/src/backend/modem-actor.test.ts +0 -95
  385. package/src/backend/modem-actor.ts +0 -112
  386. package/src/backend/nm-auto-apn.ts +0 -161
  387. package/src/backend/nm-gsm-fields.ts +0 -122
  388. package/src/backend/nmcli-nm-port.ts +0 -228
  389. package/src/backend/nmcli-runner.ts +0 -52
  390. package/src/backend/observer.ts +0 -297
  391. package/src/backend/power-contract.test.ts +0 -40
  392. package/src/backend/power-contract.ts +0 -83
  393. package/src/backend/recovery-attribution.test.ts +0 -102
  394. package/src/backend/recovery-attribution.ts +0 -86
  395. package/src/backend/recovery-budget.test.ts +0 -64
  396. package/src/backend/recovery-budget.ts +0 -84
  397. package/src/backend/recovery-ladder.test.ts +0 -257
  398. package/src/backend/recovery-ladder.ts +0 -249
  399. package/src/backend/router-ethernet.test.ts +0 -71
  400. package/src/backend/router-ethernet.ts +0 -90
  401. package/src/backend/row-store.ts +0 -105
  402. package/src/backend/signal-setup.ts +0 -112
  403. package/src/backend/sim-unlock.ts +0 -193
  404. package/src/backend/transition-preconditions.ts +0 -149
  405. package/src/backend/usage/accounting.test.ts +0 -147
  406. package/src/backend/usage/accounting.ts +0 -123
  407. package/src/backend/usage/billing-cycle.test.ts +0 -62
  408. package/src/backend/usage/billing-cycle.ts +0 -45
  409. package/src/backend/usage/index.ts +0 -37
  410. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  411. package/src/backend/usage/sampler.test.ts +0 -219
  412. package/src/backend/usage/sampler.ts +0 -228
  413. package/src/backend/usage/store.test.ts +0 -148
  414. package/src/backend/usage/store.ts +0 -177
  415. package/src/backend/usb-enumerator.test.ts +0 -87
  416. package/src/backend/usb-enumerator.ts +0 -181
  417. package/src/backend/usb-mode-transition.test.ts +0 -323
  418. package/src/backend/usb-mode-transition.ts +0 -253
  419. package/src/domain/brand.ts +0 -29
  420. package/src/domain/errors.ts +0 -77
  421. package/src/domain/guards.test.ts +0 -218
  422. package/src/domain/guards.ts +0 -144
  423. package/src/domain/identity.test.ts +0 -83
  424. package/src/domain/identity.ts +0 -165
  425. package/src/domain/index.ts +0 -12
  426. package/src/domain/snapshot.test.ts +0 -266
  427. package/src/domain/snapshot.ts +0 -120
  428. package/src/index.test.ts +0 -6
  429. package/src/index.ts +0 -15
  430. package/src/ports/README.md +0 -61
  431. package/src/ports/forbidden-surface.test.ts +0 -241
  432. package/src/ports/modem-manager.ts +0 -72
  433. package/src/ports/network-manager.ts +0 -87
  434. package/src/ports/ops.ts +0 -60
  435. package/src/ports/ops.type-test.ts +0 -39
  436. package/src/ports/receipts.test.ts +0 -153
  437. package/src/ports/reconcile.test.ts +0 -152
  438. package/src/ports/reconcile.ts +0 -338
  439. package/src/ports/router.ts +0 -29
  440. package/src/redact.test.ts +0 -82
  441. package/src/redact.ts +0 -73
  442. package/src/transport/README.md +0 -65
  443. package/src/transport/calls.ts +0 -113
  444. package/src/transport/characterization.test.ts +0 -260
  445. package/src/transport/codec.test.ts +0 -118
  446. package/src/transport/codec.ts +0 -240
  447. package/src/transport/conformance-python.test.ts +0 -152
  448. package/src/transport/conformance-same-lib.test.ts +0 -115
  449. package/src/transport/dbus-native-lib.d.ts +0 -19
  450. package/src/transport/dbus-native.ts +0 -85
  451. package/src/transport/index.ts +0 -30
  452. package/src/transport/no-library-leak.test.ts +0 -61
  453. package/src/transport/reliability.test.ts +0 -173
  454. package/src/transport/signals.ts +0 -150
  455. package/src/transport/signature.ts +0 -110
  456. package/src/transport/test-support/fake-service.ts +0 -168
  457. package/src/transport/test-support/independent-producer.py +0 -110
  458. package/src/transport/test-support/private-bus.ts +0 -66
  459. package/src/transport/transport.ts +0 -250
  460. package/src/transport/types.ts +0 -118
  461. package/src/usb-mode/catalog-schema.test.ts +0 -181
  462. package/src/usb-mode/catalog-schema.ts +0 -113
  463. package/src/usb-mode/certified-catalog.json +0 -67
  464. package/src/usb-mode/index.ts +0 -27
@@ -0,0 +1,53 @@
1
+ import type { Brand } from './brand.js';
2
+ import type { ModemIdentity } from './identity.js';
3
+ import type { DataInterface, MmState, NmActivation, Presence, RadioPower, ReconcileStatus, RecoveryState, Registration, SimSlot, SourceHealth } from './state.js';
4
+ /** A monotonically increasing snapshot revision. */
5
+ export type Revision = Brand<number, 'Revision'>;
6
+ /** Construct a `Revision` from a non-negative integer. */
7
+ export declare function revision(value: number): Revision;
8
+ /** The revision every fresh identity starts at. */
9
+ export declare const INITIAL_REVISION: Revision;
10
+ /** The next revision after `current`. */
11
+ export declare function nextRevision(current: Revision): Revision;
12
+ /** The full coherent state of one modem at one point in time. */
13
+ export interface CellularSnapshot {
14
+ readonly identity: ModemIdentity;
15
+ readonly presence: Presence;
16
+ readonly sourceHealth: SourceHealth;
17
+ readonly simSlots: readonly SimSlot[];
18
+ readonly radioPower: RadioPower;
19
+ readonly mmState: MmState;
20
+ readonly registration: Registration;
21
+ readonly nmActivation: NmActivation;
22
+ readonly dataInterface: DataInterface;
23
+ readonly reconcileStatus: ReconcileStatus;
24
+ readonly recoveryState: RecoveryState;
25
+ readonly revision: Revision;
26
+ }
27
+ /** A partial update to a snapshot's dimensions; `revision` is managed, not patched. */
28
+ export type SnapshotPatch = Partial<Omit<CellularSnapshot, 'revision'>>;
29
+ /**
30
+ * Validate and return a snapshot. The guards run here: an impossible combination
31
+ * throws `ImpossibleStateError` rather than producing an incoherent value. This
32
+ * is the sole sanctioned constructor for an arbitrary snapshot.
33
+ */
34
+ export declare function createSnapshot(fields: CellularSnapshot): CellularSnapshot;
35
+ /** A valid baseline for a freshly-observed-but-absent modem, at revision 0. */
36
+ export declare function initialSnapshot(identity: ModemIdentity): CellularSnapshot;
37
+ /**
38
+ * Apply a dimension patch, bump the revision, and re-validate. Monotonicity is
39
+ * automatic (revision always advances by one); an impossible result throws.
40
+ */
41
+ export declare function applyTransition(prev: CellularSnapshot, patch: SnapshotPatch): CellularSnapshot;
42
+ /**
43
+ * Replace a snapshot with a fully-formed successor that carries its own revision
44
+ * (the observer path). Enforces strict monotonicity — a stale or equal revision
45
+ * throws `RevisionMonotonicityError` — and validates the successor.
46
+ */
47
+ export declare function supersede(prev: CellularSnapshot, next: CellularSnapshot): CellularSnapshot;
48
+ /**
49
+ * The source (MM daemon / bus) dropped: mark the data `sourceUnavailable` while
50
+ * KEEPING presence and all other facts. Stale is never removal — only an
51
+ * authoritative snapshot confirms absence (draft §Oracle round-1 lifecycle).
52
+ */
53
+ export declare function markSourceUnavailable(prev: CellularSnapshot): CellularSnapshot;
@@ -0,0 +1,75 @@
1
+ // CellularSnapshot — the whole coherent state of one modem at one revision.
2
+ //
3
+ // A snapshot composes the identity and all eight orthogonal dimensions plus a
4
+ // monotonic `revision`. Every snapshot that exists has passed the guards: the
5
+ // constructors here are the ONLY sanctioned way to build or advance one, so an
6
+ // impossible combination can never be observed downstream. Revisions strictly
7
+ // increase, letting the observer (A3.1) and consumers order and dedupe events.
8
+ import { nonNegativeInteger } from './brand.js';
9
+ import { RevisionMonotonicityError } from './errors.js';
10
+ import { assertSnapshot } from './guards.js';
11
+ /** Construct a `Revision` from a non-negative integer. */
12
+ export function revision(value) {
13
+ return nonNegativeInteger(value, 'revision');
14
+ }
15
+ /** The revision every fresh identity starts at. */
16
+ export const INITIAL_REVISION = revision(0);
17
+ /** The next revision after `current`. */
18
+ export function nextRevision(current) {
19
+ return (current + 1);
20
+ }
21
+ /**
22
+ * Validate and return a snapshot. The guards run here: an impossible combination
23
+ * throws `ImpossibleStateError` rather than producing an incoherent value. This
24
+ * is the sole sanctioned constructor for an arbitrary snapshot.
25
+ */
26
+ export function createSnapshot(fields) {
27
+ assertSnapshot(fields);
28
+ return fields;
29
+ }
30
+ /** A valid baseline for a freshly-observed-but-absent modem, at revision 0. */
31
+ export function initialSnapshot(identity) {
32
+ return {
33
+ identity,
34
+ presence: 'absent',
35
+ sourceHealth: 'live',
36
+ simSlots: [],
37
+ radioPower: 'unknown',
38
+ mmState: 'unknown',
39
+ registration: { status: 'unknown', activeRats: new Set() },
40
+ nmActivation: 'unavailable',
41
+ dataInterface: { present: false },
42
+ reconcileStatus: 'pending',
43
+ recoveryState: { stage: 'idle', attempts: 0 },
44
+ revision: INITIAL_REVISION,
45
+ };
46
+ }
47
+ /**
48
+ * Apply a dimension patch, bump the revision, and re-validate. Monotonicity is
49
+ * automatic (revision always advances by one); an impossible result throws.
50
+ */
51
+ export function applyTransition(prev, patch) {
52
+ const next = { ...prev, ...patch, revision: nextRevision(prev.revision) };
53
+ assertSnapshot(next);
54
+ return next;
55
+ }
56
+ /**
57
+ * Replace a snapshot with a fully-formed successor that carries its own revision
58
+ * (the observer path). Enforces strict monotonicity — a stale or equal revision
59
+ * throws `RevisionMonotonicityError` — and validates the successor.
60
+ */
61
+ export function supersede(prev, next) {
62
+ if (next.revision <= prev.revision) {
63
+ throw new RevisionMonotonicityError(prev.revision, next.revision);
64
+ }
65
+ assertSnapshot(next);
66
+ return next;
67
+ }
68
+ /**
69
+ * The source (MM daemon / bus) dropped: mark the data `sourceUnavailable` while
70
+ * KEEPING presence and all other facts. Stale is never removal — only an
71
+ * authoritative snapshot confirms absence (draft §Oracle round-1 lifecycle).
72
+ */
73
+ export function markSourceUnavailable(prev) {
74
+ return applyTransition(prev, { sourceHealth: 'sourceUnavailable' });
75
+ }
@@ -1,28 +1,10 @@
1
- // Orthogonal state dimensions.
2
- //
3
- // Draft §Oracle round-1: modem state is NOT one enum. It is a set of independent
4
- // dimensions that vary separately — presence, SIM, radio, registration,
5
- // NM-activation, data interface, reconcile, recovery. Collapsing them into a
6
- // single enum loses real, simultaneously-true facts (e.g. "present + radio on +
7
- // searching + no NM connection"). Each dimension below mirrors a real
8
- // ModemManager / NetworkManager concept; values track those enums.
9
-
10
- import type { Brand } from './brand';
11
- import { nonNegativeInteger } from './brand';
12
-
1
+ import type { Brand } from './brand.js';
13
2
  /** Milliseconds since the Unix epoch. */
14
3
  export type EpochMillis = Brand<number, 'EpochMillis'>;
15
-
16
4
  /** Construct an `EpochMillis` from a non-negative integer timestamp. */
17
- export function epochMillis(value: number): EpochMillis {
18
- return nonNegativeInteger(value, 'epochMillis') as EpochMillis;
19
- }
20
-
21
- // --- 1. presence + source health -------------------------------------------
22
-
5
+ export declare function epochMillis(value: number): EpochMillis;
23
6
  /** Whether the modem is in the current authoritative observation snapshot. */
24
7
  export type Presence = 'present' | 'absent';
25
-
26
8
  /**
27
9
  * Health of the observation SOURCE (the ModemManager daemon / bus), independent
28
10
  * of presence. When the source drops (owner loss, bus disconnect) the last data
@@ -30,128 +12,59 @@ export type Presence = 'present' | 'absent';
30
12
  * `absent`. Only an authoritative snapshot confirms real removal (A3.1 epochs).
31
13
  */
32
14
  export type SourceHealth = 'live' | 'stale' | 'sourceUnavailable';
33
-
34
- // --- 2. SIM slots + lock ----------------------------------------------------
35
-
36
15
  /** SIM lock state — subset of `MMModemLock` plus `unknown`. */
37
- export type SimLock =
38
- | 'unknown'
39
- | 'none'
40
- | 'sim-pin'
41
- | 'sim-puk'
42
- | 'sim-pin2'
43
- | 'sim-puk2'
44
- | 'net-pers'
45
- | 'permanently-blocked';
46
-
16
+ export type SimLock = 'unknown' | 'none' | 'sim-pin' | 'sim-puk' | 'sim-pin2' | 'sim-puk2' | 'net-pers' | 'permanently-blocked';
47
17
  /** A single physical SIM slot. */
48
18
  export interface SimSlot {
49
- /** 1-based slot index (ModemManager numbers slots from 1). */
50
- readonly index: number;
51
- /** A SIM card is physically inserted in this slot. */
52
- readonly occupied: boolean;
53
- /** This is the primary/active slot the modem is currently using. */
54
- readonly active: boolean;
55
- readonly lock: SimLock;
19
+ /** 1-based slot index (ModemManager numbers slots from 1). */
20
+ readonly index: number;
21
+ /** A SIM card is physically inserted in this slot. */
22
+ readonly occupied: boolean;
23
+ /** This is the primary/active slot the modem is currently using. */
24
+ readonly active: boolean;
25
+ readonly lock: SimLock;
56
26
  }
57
-
58
27
  /** Lock states that require a SIM to actually be present in the slot. */
59
- export const SIM_LOCK_REQUIRES_CARD: ReadonlySet<SimLock> = new Set<SimLock>([
60
- 'sim-pin',
61
- 'sim-puk',
62
- 'sim-pin2',
63
- 'sim-puk2',
64
- 'net-pers',
65
- 'permanently-blocked',
66
- ]);
67
-
68
- // --- 3. radio power + MM state ---------------------------------------------
69
-
28
+ export declare const SIM_LOCK_REQUIRES_CARD: ReadonlySet<SimLock>;
70
29
  /** Radio power state — `MMModemPowerState`. */
71
30
  export type RadioPower = 'unknown' | 'off' | 'low' | 'on';
72
-
73
31
  /** Modem lifecycle state — `MMModemState`. */
74
- export type MmState =
75
- | 'failed'
76
- | 'unknown'
77
- | 'initializing'
78
- | 'locked'
79
- | 'disabled'
80
- | 'disabling'
81
- | 'enabling'
82
- | 'enabled'
83
- | 'searching'
84
- | 'registered'
85
- | 'disconnecting'
86
- | 'connecting'
87
- | 'connected';
88
-
32
+ export type MmState = 'failed' | 'unknown' | 'initializing' | 'locked' | 'disabled' | 'disabling' | 'enabling' | 'enabled' | 'searching' | 'registered' | 'disconnecting' | 'connecting' | 'connected';
89
33
  /**
90
34
  * MM states that imply the radio is powered and actively on the air — none of
91
35
  * these can coexist with `radioPower: 'off'`, and all imply the modem is present.
92
36
  */
93
- export const MM_STATES_REQUIRING_RADIO: ReadonlySet<MmState> = new Set<MmState>([
94
- 'enabled',
95
- 'searching',
96
- 'registered',
97
- 'connecting',
98
- 'connected',
99
- 'disconnecting',
100
- ]);
101
-
102
- // --- 4. registration + RAT set ---------------------------------------------
103
-
37
+ export declare const MM_STATES_REQUIRING_RADIO: ReadonlySet<MmState>;
104
38
  /** 3GPP registration state — `MMModem3gppRegistrationState`. */
105
39
  export type RegistrationStatus = 'idle' | 'home' | 'searching' | 'denied' | 'unknown' | 'roaming';
106
-
107
40
  /** Radio access technology family — subset of `MMModemAccessTechnology` groups. */
108
41
  export type RadioAccessTechnology = 'gsm' | 'umts' | 'lte' | '5gnr';
109
-
110
42
  /**
111
43
  * Registration dimension: a status plus the SET of currently-active access
112
44
  * technologies. MM's access-technology field is a bitmask (carrier aggregation
113
45
  * can light more than one), so a set — not a single value — is the faithful model.
114
46
  */
115
47
  export interface Registration {
116
- readonly status: RegistrationStatus;
117
- readonly activeRats: ReadonlySet<RadioAccessTechnology>;
48
+ readonly status: RegistrationStatus;
49
+ readonly activeRats: ReadonlySet<RadioAccessTechnology>;
118
50
  }
119
-
120
51
  /** Registration statuses that mean the modem is attached to a network. */
121
- export function isRegistered(status: RegistrationStatus): boolean {
122
- return status === 'home' || status === 'roaming';
123
- }
124
-
125
- // --- 5. NM activation -------------------------------------------------------
126
-
52
+ export declare function isRegistered(status: RegistrationStatus): boolean;
127
53
  /**
128
54
  * NetworkManager connection/activation state for this modem's device — `NMDeviceState`
129
55
  * collapsed to the states that matter. NM is the SOLE owner of activation; this
130
56
  * dimension reflects, never drives, that ownership.
131
57
  */
132
- export type NmActivation =
133
- | 'unmanaged'
134
- | 'unavailable'
135
- | 'disconnected'
136
- | 'activating'
137
- | 'activated'
138
- | 'deactivating'
139
- | 'failed';
140
-
141
- // --- 6. data interface ------------------------------------------------------
142
-
58
+ export type NmActivation = 'unmanaged' | 'unavailable' | 'disconnected' | 'activating' | 'activated' | 'deactivating' | 'failed';
143
59
  /**
144
60
  * The net device the modem exposes for data (e.g. `wwan0`). `name` may be absent
145
61
  * even when `present` (MM can report a bearer whose ip-interface is not yet
146
62
  * named); a `name` without `present` is impossible and guarded.
147
63
  */
148
64
  export interface DataInterface {
149
- readonly present: boolean;
150
- readonly name?: string;
65
+ readonly present: boolean;
66
+ readonly name?: string;
151
67
  }
152
-
153
- // --- 7. reconcile status ----------------------------------------------------
154
-
155
68
  /**
156
69
  * Aggregate desired-state reconciliation status. Mirrors the A2.2 receipt
157
70
  * taxonomy at snapshot granularity: `unsupported` means the desired state cannot
@@ -159,31 +72,19 @@ export interface DataInterface {
159
72
  * never silently dropped.
160
73
  */
161
74
  export type ReconcileStatus = 'converged' | 'reconciling' | 'pending' | 'divergent' | 'unsupported';
162
-
163
- // --- 8. recovery state ------------------------------------------------------
164
-
165
75
  /**
166
76
  * Recovery-ladder stage. Ordered rungs mirror A3.4:
167
77
  * nm-cycle → mm-cycle → reset → power-cycle, gated by attribution and budgets.
168
78
  * `idle` = nothing in flight; `exhausted` = budget spent, gave up.
169
79
  */
170
- export type RecoveryStage =
171
- | 'idle'
172
- | 'attributing'
173
- | 'nm-cycle'
174
- | 'mm-cycle'
175
- | 'reset'
176
- | 'power-cycle'
177
- | 'cooldown'
178
- | 'exhausted';
179
-
80
+ export type RecoveryStage = 'idle' | 'attributing' | 'nm-cycle' | 'mm-cycle' | 'reset' | 'power-cycle' | 'cooldown' | 'exhausted';
180
81
  /**
181
82
  * Recovery dimension. `cooldownUntil` is present ONLY while `stage` is `cooldown`
182
83
  * (guarded); `attempts` counts disruptive rungs fired in the current budget window
183
84
  * and resets to 0 at `idle`.
184
85
  */
185
86
  export interface RecoveryState {
186
- readonly stage: RecoveryStage;
187
- readonly attempts: number;
188
- readonly cooldownUntil?: EpochMillis;
87
+ readonly stage: RecoveryStage;
88
+ readonly attempts: number;
89
+ readonly cooldownUntil?: EpochMillis;
189
90
  }
@@ -0,0 +1,38 @@
1
+ // Orthogonal state dimensions.
2
+ //
3
+ // Draft §Oracle round-1: modem state is NOT one enum. It is a set of independent
4
+ // dimensions that vary separately — presence, SIM, radio, registration,
5
+ // NM-activation, data interface, reconcile, recovery. Collapsing them into a
6
+ // single enum loses real, simultaneously-true facts (e.g. "present + radio on +
7
+ // searching + no NM connection"). Each dimension below mirrors a real
8
+ // ModemManager / NetworkManager concept; values track those enums.
9
+ import { nonNegativeInteger } from './brand.js';
10
+ /** Construct an `EpochMillis` from a non-negative integer timestamp. */
11
+ export function epochMillis(value) {
12
+ return nonNegativeInteger(value, 'epochMillis');
13
+ }
14
+ /** Lock states that require a SIM to actually be present in the slot. */
15
+ export const SIM_LOCK_REQUIRES_CARD = new Set([
16
+ 'sim-pin',
17
+ 'sim-puk',
18
+ 'sim-pin2',
19
+ 'sim-puk2',
20
+ 'net-pers',
21
+ 'permanently-blocked',
22
+ ]);
23
+ /**
24
+ * MM states that imply the radio is powered and actively on the air — none of
25
+ * these can coexist with `radioPower: 'off'`, and all imply the modem is present.
26
+ */
27
+ export const MM_STATES_REQUIRING_RADIO = new Set([
28
+ 'enabled',
29
+ 'searching',
30
+ 'registered',
31
+ 'connecting',
32
+ 'connected',
33
+ 'disconnecting',
34
+ ]);
35
+ /** Registration statuses that mean the modem is attached to a network. */
36
+ export function isRegistered(status) {
37
+ return status === 'home' || status === 'roaming';
38
+ }
@@ -0,0 +1,63 @@
1
+ /** The four vendor scripts ModemManager 1.24.2 ships, and what each one drives. */
2
+ export declare const MM_FCC_UNLOCK_VENDOR_SCRIPTS: {
3
+ readonly '105b': "mbimcli";
4
+ readonly '1199': "qmicli";
5
+ readonly '14c3': "mbimcli";
6
+ readonly '2c7c': "qmicli";
7
+ };
8
+ export type MmFccUnlockVendorScript = keyof typeof MM_FCC_UNLOCK_VENDOR_SCRIPTS;
9
+ /** The interpreters those scripts invoke, and the packages that provide them. */
10
+ export declare const MM_FCC_UNLOCK_RUNTIME_PACKAGES: {
11
+ readonly qmicli: "libqmi-utils";
12
+ readonly mbimcli: "libmbim-utils";
13
+ };
14
+ /**
15
+ * ModemManager 1.24.2's COMPLETE shipped mapping — `data/dispatcher-fcc-unlock/
16
+ * meson.build`'s `vidpids` dict, verbatim. Fourteen entries; there are no others.
17
+ */
18
+ export declare const MM_FCC_UNLOCK_COVERAGE: {
19
+ readonly '03f0:4e1d': "1199";
20
+ readonly '105b:e0ab': "105b";
21
+ readonly '105b:e0c3': "105b";
22
+ readonly '1199:9079': "1199";
23
+ readonly '14c3:4d75': "14c3";
24
+ readonly '1eac:1001': "2c7c";
25
+ readonly '1eac:1004': "2c7c";
26
+ readonly '1eac:1007': "2c7c";
27
+ readonly '2c7c:030a': "2c7c";
28
+ readonly '2c7c:0313': "2c7c";
29
+ readonly '2c7c:0314': "2c7c";
30
+ readonly '2c7c:0801': "2c7c";
31
+ readonly '413c:81a3': "1199";
32
+ readonly '413c:81a8': "1199";
33
+ };
34
+ export type MmFccUnlockKey = keyof typeof MM_FCC_UNLOCK_COVERAGE;
35
+ /**
36
+ * Fold a vid/pid pair into the dispatcher's key, or `undefined` when it is not a
37
+ * pair of 4-hex ids. Case is folded because sysfs and udev disagree about it
38
+ * (`ID_VENDOR_ID` is lowercase, some vendor strings are not) while the dispatcher's
39
+ * `%04x` is unambiguously lowercase; a `0x` prefix is tolerated for the same reason.
40
+ * NOTHING ELSE is normalized — a 3-digit or 5-digit id is a different device, not a
41
+ * sloppy spelling of this one.
42
+ */
43
+ export declare function normalizeVidPid(vid: string, pid: string): string | undefined;
44
+ /** True for a string already in the dispatcher's `<vid>:<pid>` shape. */
45
+ export declare function isFccUnlockKey(value: string): boolean;
46
+ /**
47
+ * Does ModemManager ship an unlock procedure for this device?
48
+ *
49
+ * The three answers are NOT interchangeable, and the third is why this returns a
50
+ * tri-state rather than a boolean:
51
+ * present — a `<vid>:<pid>` entry exists; the toggle can do something.
52
+ * absent — the ids are well-formed and are NOT in the mapping. A positive
53
+ * statement about the device, so the module reads `unavailable` and no
54
+ * control is offered.
55
+ * unknown — we could not read the ids at all. That is a statement about the READ,
56
+ * and reporting it as `absent` would hide the module on hardware that
57
+ * may well be covered.
58
+ */
59
+ export declare function resolveFccUnlockCoverage(vid: string | undefined, pid: string | undefined): 'present' | 'absent' | 'unknown';
60
+ /** The vendor script a covered key resolves to, for diagnostics and docs. */
61
+ export declare function fccUnlockVendorScript(key: string): MmFccUnlockVendorScript | undefined;
62
+ /** The interpreter a covered key's script invokes (`qmicli` / `mbimcli`). */
63
+ export declare function fccUnlockRuntimeBinary(key: string): 'qmicli' | 'mbimcli' | undefined;
@@ -0,0 +1,102 @@
1
+ // The FCC-unlock COVERAGE CATALOG — which `<vid>:<pid>` ModemManager can unlock.
2
+ //
3
+ // This is the evidence source for the `fcc-auto-unlock` capability module.
4
+ // `capability/detect.ts` answers `unknown` for that module on purpose and says why:
5
+ // FCC unlock is carried out by a ModemManager DISPATCHER keyed on the device, and
6
+ // nothing on the modem's own D-Bus surface says whether a procedure applies. So the
7
+ // answer has to come from a catalog, and this is it.
8
+ //
9
+ // Pinned to ModemManager 1.24.2 (`packaging/upstream-pins.yaml`) — the exact release
10
+ // this repository rebuilds. Prose walkthrough, per-device fleet verdicts and the
11
+ // market table: `docs/FCC-UNLOCK-COVERAGE.md`.
12
+ //
13
+ // THE KEY IS `<vid>:<pid>` AND NOTHING ELSE. `mm-dispatcher-fcc-unlock.c` builds
14
+ // exactly one filename — `g_strdup_printf("%04x:%04x", vid, pid)` — and looks for it
15
+ // in the two enabled tiers. A vendor-only name is never opened by the dispatcher; it
16
+ // only ever exists as the TARGET of a `<vid>:<pid>` link in the available tier. And a
17
+ // vendor-keyed rule would be wrong twice over: Sierra silicon ships under three
18
+ // vendor ids (`1199` its own, `03f0` HP-branded, `413c` Dell-branded), so keying on
19
+ // the vendor misses two of the three, while keying on the model misses the rebrands.
20
+ /** The four vendor scripts ModemManager 1.24.2 ships, and what each one drives. */
21
+ export const MM_FCC_UNLOCK_VENDOR_SCRIPTS = {
22
+ '105b': 'mbimcli',
23
+ '1199': 'qmicli',
24
+ '14c3': 'mbimcli',
25
+ '2c7c': 'qmicli',
26
+ };
27
+ /** The interpreters those scripts invoke, and the packages that provide them. */
28
+ export const MM_FCC_UNLOCK_RUNTIME_PACKAGES = {
29
+ qmicli: 'libqmi-utils',
30
+ mbimcli: 'libmbim-utils',
31
+ };
32
+ /**
33
+ * ModemManager 1.24.2's COMPLETE shipped mapping — `data/dispatcher-fcc-unlock/
34
+ * meson.build`'s `vidpids` dict, verbatim. Fourteen entries; there are no others.
35
+ */
36
+ export const MM_FCC_UNLOCK_COVERAGE = {
37
+ '03f0:4e1d': '1199',
38
+ '105b:e0ab': '105b',
39
+ '105b:e0c3': '105b',
40
+ '1199:9079': '1199',
41
+ '14c3:4d75': '14c3',
42
+ '1eac:1001': '2c7c',
43
+ '1eac:1004': '2c7c',
44
+ '1eac:1007': '2c7c',
45
+ '2c7c:030a': '2c7c',
46
+ '2c7c:0313': '2c7c',
47
+ '2c7c:0314': '2c7c',
48
+ '2c7c:0801': '2c7c',
49
+ '413c:81a3': '1199',
50
+ '413c:81a8': '1199',
51
+ };
52
+ /** `<4 lowercase hex>:<4 lowercase hex>` — the dispatcher's own filename shape. */
53
+ const VID_PID_RE = /^[0-9a-f]{4}:[0-9a-f]{4}$/;
54
+ /**
55
+ * Fold a vid/pid pair into the dispatcher's key, or `undefined` when it is not a
56
+ * pair of 4-hex ids. Case is folded because sysfs and udev disagree about it
57
+ * (`ID_VENDOR_ID` is lowercase, some vendor strings are not) while the dispatcher's
58
+ * `%04x` is unambiguously lowercase; a `0x` prefix is tolerated for the same reason.
59
+ * NOTHING ELSE is normalized — a 3-digit or 5-digit id is a different device, not a
60
+ * sloppy spelling of this one.
61
+ */
62
+ export function normalizeVidPid(vid, pid) {
63
+ const fold = (raw) => raw.trim().toLowerCase().replace(/^0x/, '');
64
+ const key = `${fold(vid)}:${fold(pid)}`;
65
+ return VID_PID_RE.test(key) ? key : undefined;
66
+ }
67
+ /** True for a string already in the dispatcher's `<vid>:<pid>` shape. */
68
+ export function isFccUnlockKey(value) {
69
+ return VID_PID_RE.test(value);
70
+ }
71
+ /**
72
+ * Does ModemManager ship an unlock procedure for this device?
73
+ *
74
+ * The three answers are NOT interchangeable, and the third is why this returns a
75
+ * tri-state rather than a boolean:
76
+ * present — a `<vid>:<pid>` entry exists; the toggle can do something.
77
+ * absent — the ids are well-formed and are NOT in the mapping. A positive
78
+ * statement about the device, so the module reads `unavailable` and no
79
+ * control is offered.
80
+ * unknown — we could not read the ids at all. That is a statement about the READ,
81
+ * and reporting it as `absent` would hide the module on hardware that
82
+ * may well be covered.
83
+ */
84
+ export function resolveFccUnlockCoverage(vid, pid) {
85
+ if (vid === undefined || pid === undefined) {
86
+ return 'unknown';
87
+ }
88
+ const key = normalizeVidPid(vid, pid);
89
+ if (key === undefined) {
90
+ return 'unknown';
91
+ }
92
+ return key in MM_FCC_UNLOCK_COVERAGE ? 'present' : 'absent';
93
+ }
94
+ /** The vendor script a covered key resolves to, for diagnostics and docs. */
95
+ export function fccUnlockVendorScript(key) {
96
+ return MM_FCC_UNLOCK_COVERAGE[key];
97
+ }
98
+ /** The interpreter a covered key's script invokes (`qmicli` / `mbimcli`). */
99
+ export function fccUnlockRuntimeBinary(key) {
100
+ const script = fccUnlockVendorScript(key);
101
+ return script === undefined ? undefined : MM_FCC_UNLOCK_VENDOR_SCRIPTS[script];
102
+ }
@@ -0,0 +1,3 @@
1
+ export * from './coverage.js';
2
+ export * from './policy-store.js';
3
+ export * from './policy-write.js';
@@ -0,0 +1,12 @@
1
+ // FCC auto-unlock — the opt-in POLICY surface, and the catalog that gates it.
2
+ //
3
+ // This module implements NO unlock procedure and ships NO unlock script. All it does
4
+ // is record which `<vid>:<pid>` models an operator has opted in for, so that
5
+ // `ceralive-fcc-reconcile` can re-derive ModemManager's own admin-tier symlinks from
6
+ // that record on every boot. The unlocking itself is ModemManager's dispatcher's job,
7
+ // start to finish.
8
+ //
9
+ // Full model, coverage matrix and certification status: `docs/FCC-UNLOCK-COVERAGE.md`.
10
+ export * from './coverage.js';
11
+ export * from './policy-store.js';
12
+ export * from './policy-write.js';
@@ -0,0 +1,40 @@
1
+ /** The current on-disk schema version. Bump when the persisted shape changes. */
2
+ export declare const FCC_UNLOCK_SCHEMA_VERSION = 1;
3
+ /** The pinned location of the policy of record. `/data` survives a slot swap. */
4
+ export declare const FCC_UNLOCK_POLICY_PATH = "/data/ceralive/fcc-unlock-policy.json";
5
+ /**
6
+ * The persisted document.
7
+ *
8
+ * `unlock` is a TOTAL map from `<vid>:<pid>` to the operator's answer. An absent key
9
+ * and an explicit `false` are the same fact (not opted in) and both are legal on
10
+ * disk: a `false` is what an opt-OUT leaves behind, and keeping it is what lets the
11
+ * shell reconciler prove it parsed a real answer rather than an empty document.
12
+ */
13
+ export interface PersistedFccUnlockPolicy {
14
+ readonly schemaVersion: typeof FCC_UNLOCK_SCHEMA_VERSION;
15
+ readonly savedAtMs: number;
16
+ readonly unlock: Readonly<Record<string, boolean>>;
17
+ }
18
+ /** A metadata-only log event. Corruption NEVER carries the raw file content. */
19
+ export type FccUnlockLogEvent = {
20
+ readonly kind: 'corrupt-policy';
21
+ readonly bytes: number;
22
+ readonly reason: string;
23
+ };
24
+ export type FccUnlockLogger = (event: FccUnlockLogEvent) => void;
25
+ /** The persistence seam `setFccUnlockPolicy` drives. */
26
+ export interface FccUnlockPolicyStore {
27
+ /** Load persisted policy; an absent or unreadable file loads as EMPTY. */
28
+ load(nowMs: number): Promise<PersistedFccUnlockPolicy>;
29
+ /** Atomically write policy with mode 0600 (temp → chmod → rename). */
30
+ save(state: PersistedFccUnlockPolicy): Promise<void>;
31
+ }
32
+ export interface FccUnlockPolicyFileStoreOptions {
33
+ readonly path?: string;
34
+ readonly logger?: FccUnlockLogger;
35
+ }
36
+ /** The `<vid>:<pid>` models the policy positively enables. Sorted, for stability. */
37
+ export declare function enabledFccUnlockKeys(state: PersistedFccUnlockPolicy): string[];
38
+ /** One model's answer. An unmentioned model is NOT enabled — absence is not consent. */
39
+ export declare function isFccUnlockEnabled(state: PersistedFccUnlockPolicy, key: string): boolean;
40
+ export declare function createFccUnlockPolicyFileStore(options?: FccUnlockPolicyFileStoreOptions): FccUnlockPolicyStore;