@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,52 @@
1
+ // Desired, applied and observed are THREE things, and this module refuses to make
2
+ // them one.
3
+ //
4
+ // The pattern is NetworkManager's: a connection PROFILE is what an operator asked
5
+ // for, an active connection's BEARER is what was actually put into force, and the
6
+ // device's own reported state is what the hardware is currently doing. All three are
7
+ // routinely different at once — a profile edited but not re-activated, a bearer that
8
+ // survived a profile change, a device that dropped registration without anything
9
+ // having been re-applied — and a merged "current state" blob has to pick one of them
10
+ // and silently lose the other two.
11
+ //
12
+ // Concretely, collapsing them makes these questions unanswerable:
13
+ // · did the operator's last change actually take effect, or is it only pending?
14
+ // · is what the device reports the consequence of our write, or of the network?
15
+ // · when a rollback is needed, what exactly do we roll back TO?
16
+ //
17
+ // So the three live in separate slots with separate `kind` discriminants, and the
18
+ // comparison below reports TWO independent divergences instead of one verdict.
19
+ // `NetworkManagerAdapter` (a later change) consumes exactly this shape.
20
+ import { viewEnvelope } from './envelope.js';
21
+ export function desiredProfile(profile, requestedAt, requestedBy) {
22
+ return { kind: 'desired', profile, requestedAt, requestedBy };
23
+ }
24
+ export function appliedConfiguration(input) {
25
+ return { kind: 'applied', ...input };
26
+ }
27
+ export function observedState(observation) {
28
+ return { kind: 'observed', observation };
29
+ }
30
+ export const STATE_VIEW_SLOTS = ['desired', 'applied', 'observed'];
31
+ export function describeStateDivergence(view, equals) {
32
+ return {
33
+ desiredVsApplied: compareSlots(view.desired === null ? undefined : view.desired.profile, view.applied === null ? undefined : view.applied.configuration, view.desired === null ? 'desired' : 'applied', equals),
34
+ appliedVsObserved: compareSlots(view.applied === null ? undefined : view.applied.configuration, observedValue(view.observed), view.applied === null ? 'applied' : 'observed', equals),
35
+ };
36
+ }
37
+ /**
38
+ * The observed value, or `undefined` when the observation carries none.
39
+ *
40
+ * An unavailable observation is `indeterminate` against anything, never `aligned`:
41
+ * "we could not read it" is not evidence that it matches.
42
+ */
43
+ function observedValue(observed) {
44
+ const view = viewEnvelope(observed.observation);
45
+ return view.kind === 'unavailable' ? undefined : view.value;
46
+ }
47
+ function compareSlots(left, right, missing, equals) {
48
+ if (left === undefined || right === undefined) {
49
+ return { status: 'indeterminate', missing };
50
+ }
51
+ return equals(left, right) ? { status: 'aligned' } : { status: 'diverged' };
52
+ }
@@ -0,0 +1,72 @@
1
+ import type { DeviceGeneration, OperationCompletion, OperationDescriptor, OperationResult, PhysicalModemId } from '../domain/index.js';
2
+ export type OperationPreconditionRequest = {
3
+ readonly operationId: string;
4
+ readonly physicalModemId: PhysicalModemId;
5
+ readonly generation: DeviceGeneration;
6
+ readonly descriptorId: string;
7
+ readonly preconditions: readonly string[];
8
+ };
9
+ export type OperationPreconditionResult = {
10
+ readonly status: 'satisfied';
11
+ } | {
12
+ readonly status: 'refused';
13
+ readonly reason: string;
14
+ };
15
+ /** Live operation facts. Implementations must inspect them for every invocation. */
16
+ export interface OperationPreconditionPort {
17
+ check(request: OperationPreconditionRequest): Promise<OperationPreconditionResult>;
18
+ }
19
+ export type OperationAttemptContext = {
20
+ readonly operationId: string;
21
+ readonly generation: DeviceGeneration;
22
+ readonly attempt: number;
23
+ };
24
+ export type OperationJournalEvent<I, O> = {
25
+ readonly phase: 'started';
26
+ readonly operationId: string;
27
+ readonly physicalModemId: PhysicalModemId;
28
+ readonly generation: DeviceGeneration;
29
+ readonly descriptor: OperationDescriptor<I, O>;
30
+ readonly input: I;
31
+ } | {
32
+ readonly phase: 'completed';
33
+ readonly operationId: string;
34
+ readonly physicalModemId: PhysicalModemId;
35
+ readonly generation: DeviceGeneration;
36
+ readonly descriptor: OperationDescriptor<I, O>;
37
+ readonly result: OperationResult<O>;
38
+ };
39
+ export interface OperationJournalHook<I, O> {
40
+ record(event: OperationJournalEvent<I, O>): Promise<void>;
41
+ }
42
+ export type OperationExecution<I, O> = {
43
+ readonly operationId: string;
44
+ readonly physicalModemId: PhysicalModemId;
45
+ readonly descriptor: OperationDescriptor<I, O>;
46
+ readonly input: I;
47
+ readonly execute: (context: OperationAttemptContext) => Promise<OperationCompletion<O>>;
48
+ readonly readback?: (context: OperationAttemptContext) => Promise<OperationCompletion<O>>;
49
+ readonly rollback?: (context: OperationAttemptContext) => Promise<OperationCompletion<void>>;
50
+ readonly journal?: OperationJournalHook<I, O>;
51
+ };
52
+ export type ReconciliationExecution = {
53
+ readonly physicalModemId: PhysicalModemId;
54
+ readonly generation: DeviceGeneration;
55
+ readonly run: () => Promise<{
56
+ readonly status: 'reconciled';
57
+ } | {
58
+ readonly status: 'failed';
59
+ readonly reason: string;
60
+ }>;
61
+ };
62
+ export type ReconciliationResult = {
63
+ readonly status: 'reconciled';
64
+ readonly generation: DeviceGeneration;
65
+ } | {
66
+ readonly status: 'not-required';
67
+ readonly generation: DeviceGeneration;
68
+ } | {
69
+ readonly status: 'failed';
70
+ readonly reason: 'stale-generation' | string;
71
+ readonly generation: DeviceGeneration;
72
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export * from './operation-engine.js';
@@ -0,0 +1 @@
1
+ export * from './operation-engine.js';
@@ -0,0 +1,16 @@
1
+ import { type DeviceGeneration, type OperationResult, type PhysicalModemId } from '../domain/index.js';
2
+ import type { ModemControlCompositionRoot } from '../safety/index.js';
3
+ import type { OperationExecution, OperationPreconditionPort, ReconciliationExecution, ReconciliationResult } from './contracts.js';
4
+ export * from './contracts.js';
5
+ export type OperationEngineOptions = {
6
+ readonly root: ModemControlCompositionRoot;
7
+ readonly currentGeneration: (physicalModemId: PhysicalModemId) => DeviceGeneration;
8
+ readonly preconditions: OperationPreconditionPort;
9
+ };
10
+ export declare class OperationEngine {
11
+ #private;
12
+ constructor(options: OperationEngineOptions);
13
+ invoke<I, O>(execution: OperationExecution<I, O>): Promise<OperationResult<O>>;
14
+ reconcile(execution: ReconciliationExecution): Promise<ReconciliationResult>;
15
+ }
16
+ export declare function createOperationEngine(options: OperationEngineOptions): OperationEngine;
@@ -0,0 +1,194 @@
1
+ import { canAutoRetry, classifyOperationCompletion, } from '../domain/index.js';
2
+ import { acquireMutationAdmission } from '../ports/index.js';
3
+ export * from './contracts.js';
4
+ const MAX_IDEMPOTENT_READ_ATTEMPTS = 2;
5
+ export class OperationEngine {
6
+ #root;
7
+ #currentGeneration;
8
+ #preconditions;
9
+ #reconciliationRequired = new Set();
10
+ constructor(options) {
11
+ this.#root = options.root;
12
+ this.#currentGeneration = options.currentGeneration;
13
+ this.#preconditions = options.preconditions;
14
+ }
15
+ invoke(execution) {
16
+ if (execution.descriptor.mutationImpact === 'read') {
17
+ return this.#invokeNow(execution);
18
+ }
19
+ return this.#root
20
+ .actorFor(execution.physicalModemId)
21
+ .run(execution.physicalModemId, () => this.#invokeNow(execution));
22
+ }
23
+ reconcile(execution) {
24
+ return this.#root
25
+ .actorFor(execution.physicalModemId)
26
+ .run(execution.physicalModemId, async () => {
27
+ const current = this.#currentGeneration(execution.physicalModemId);
28
+ if (!this.#reconciliationRequired.has(execution.physicalModemId)) {
29
+ return { status: 'not-required', generation: current };
30
+ }
31
+ if (current !== execution.generation) {
32
+ return { status: 'failed', reason: 'stale-generation', generation: current };
33
+ }
34
+ const result = await execution.run();
35
+ const completedGeneration = this.#currentGeneration(execution.physicalModemId);
36
+ if (completedGeneration !== execution.generation) {
37
+ return {
38
+ status: 'failed',
39
+ reason: 'stale-generation',
40
+ generation: completedGeneration,
41
+ };
42
+ }
43
+ if (result.status === 'failed') {
44
+ return { ...result, generation: completedGeneration };
45
+ }
46
+ this.#reconciliationRequired.delete(execution.physicalModemId);
47
+ return { status: 'reconciled', generation: completedGeneration };
48
+ });
49
+ }
50
+ async #invokeNow(execution) {
51
+ const generation = this.#currentGeneration(execution.physicalModemId);
52
+ const kind = execution.descriptor.mutationImpact === 'read' ? 'read' : 'write';
53
+ if (kind === 'write' && this.#reconciliationRequired.has(execution.physicalModemId)) {
54
+ return refused('reconciliation-required', generation);
55
+ }
56
+ const descriptorRefusal = descriptorRefusalReason(execution);
57
+ if (descriptorRefusal !== undefined)
58
+ return refused(descriptorRefusal, generation);
59
+ const precondition = await this.#preconditions.check({
60
+ operationId: execution.operationId,
61
+ physicalModemId: execution.physicalModemId,
62
+ generation,
63
+ descriptorId: execution.descriptor.id,
64
+ preconditions: execution.descriptor.livePreconditions,
65
+ });
66
+ if (precondition.status === 'refused')
67
+ return refused(precondition.reason, generation);
68
+ const admission = await acquireMutationAdmission({
69
+ operationId: execution.operationId,
70
+ physicalModemId: execution.physicalModemId,
71
+ impact: execution.descriptor.mutationImpact,
72
+ requirement: execution.descriptor.admission,
73
+ }, kind === 'write' ? this.#root.admission : undefined);
74
+ if (admission.status === 'refused')
75
+ return refused(admission.reason, generation);
76
+ try {
77
+ await execution.journal?.record({
78
+ phase: 'started',
79
+ operationId: execution.operationId,
80
+ physicalModemId: execution.physicalModemId,
81
+ generation,
82
+ descriptor: execution.descriptor,
83
+ input: execution.input,
84
+ });
85
+ const result = await this.#executeWithRetry(execution, generation, kind);
86
+ const withHooks = await this.#runCompletionHooks(execution, result, generation);
87
+ if (withHooks.status === 'unknown-outcome') {
88
+ this.#reconciliationRequired.add(execution.physicalModemId);
89
+ }
90
+ await execution.journal?.record({
91
+ phase: 'completed',
92
+ operationId: execution.operationId,
93
+ physicalModemId: execution.physicalModemId,
94
+ generation,
95
+ descriptor: execution.descriptor,
96
+ result: withHooks,
97
+ });
98
+ return withHooks;
99
+ }
100
+ finally {
101
+ await releaseAdmission(admission);
102
+ }
103
+ }
104
+ async #executeWithRetry(execution, generation, kind) {
105
+ for (let attempt = 1; attempt <= MAX_IDEMPOTENT_READ_ATTEMPTS; attempt += 1) {
106
+ const completion = await execution.execute({
107
+ operationId: execution.operationId,
108
+ generation,
109
+ attempt,
110
+ });
111
+ const result = classifyOperationCompletion({
112
+ operation: kind,
113
+ completionGeneration: generation,
114
+ currentGeneration: this.#currentGeneration(execution.physicalModemId),
115
+ completion,
116
+ });
117
+ if (!canAutoRetry(execution.descriptor, result) || attempt === MAX_IDEMPOTENT_READ_ATTEMPTS) {
118
+ return result;
119
+ }
120
+ }
121
+ return refused('retry-budget-exhausted', generation);
122
+ }
123
+ async #runCompletionHooks(execution, result, generation) {
124
+ const context = {
125
+ operationId: execution.operationId,
126
+ generation,
127
+ attempt: 1,
128
+ };
129
+ if (result.status === 'applied' && execution.descriptor.readback.required) {
130
+ const completion = await execution.readback?.(context);
131
+ if (completion === undefined)
132
+ return refused('readback-hook-missing', generation);
133
+ const readback = classifyOperationCompletion({
134
+ operation: 'read',
135
+ completionGeneration: generation,
136
+ currentGeneration: this.#currentGeneration(execution.physicalModemId),
137
+ completion,
138
+ });
139
+ if (readback.status === 'applied' &&
140
+ execution.descriptor.readback.matches(execution.input, readback.value)) {
141
+ return result;
142
+ }
143
+ if (readback.status === 'unknown-outcome')
144
+ return readback;
145
+ await execution.rollback?.(context);
146
+ return refused(readback.status === 'applied' ? 'readback-mismatch' : `readback-${readback.reason}`, generation, 'failed');
147
+ }
148
+ if (result.status === 'failed' && execution.descriptor.rollback.required) {
149
+ await execution.rollback?.(context);
150
+ }
151
+ return result;
152
+ }
153
+ }
154
+ export function createOperationEngine(options) {
155
+ return new OperationEngine(options);
156
+ }
157
+ function descriptorRefusalReason(execution) {
158
+ const { descriptor } = execution;
159
+ const support = descriptor.mutationImpact === 'read' ? descriptor.support.read : descriptor.support.write;
160
+ if (!support.supported)
161
+ return support.reason;
162
+ if (descriptor.availability.state !== 'available')
163
+ return descriptor.availability.reason;
164
+ if (!inputAllowed(descriptor, execution.input))
165
+ return 'constraint-refused';
166
+ if (descriptor.readback.required && execution.readback === undefined)
167
+ return 'readback-hook-missing';
168
+ if (descriptor.rollback.required && execution.rollback === undefined)
169
+ return 'rollback-hook-missing';
170
+ if (descriptor.journal.required && execution.journal === undefined)
171
+ return 'journal-hook-missing';
172
+ return undefined;
173
+ }
174
+ function inputAllowed(descriptor, input) {
175
+ switch (descriptor.constraints.kind) {
176
+ case 'unconstrained':
177
+ return true;
178
+ case 'allowed-values':
179
+ return descriptor.constraints.values.some((value) => Object.is(value, input));
180
+ case 'numeric-range':
181
+ return (typeof input === 'number' &&
182
+ input >= descriptor.constraints.min &&
183
+ input <= descriptor.constraints.max &&
184
+ (descriptor.constraints.step === undefined ||
185
+ (input - descriptor.constraints.min) % descriptor.constraints.step === 0));
186
+ }
187
+ }
188
+ function refused(reason, generation, status = 'refused') {
189
+ return { status, reason, generation, requiresReconciliation: false };
190
+ }
191
+ async function releaseAdmission(admission) {
192
+ if (admission.status === 'admitted')
193
+ await admission.lease.release();
194
+ }
@@ -0,0 +1,12 @@
1
+ export * from './location.js';
2
+ export * from './modem-manager.js';
3
+ export * from './mutation-admission.js';
4
+ export * from './network-manager.js';
5
+ export * from './observation.js';
6
+ export * from './ops.js';
7
+ export * from './receipts.js';
8
+ export * from './reconcile.js';
9
+ export * from './resource-ownership.js';
10
+ export * from './router.js';
11
+ export * from './sms.js';
12
+ export * from './uhubctl.js';
@@ -6,11 +6,15 @@
6
6
  // autoconnect / activation; MM owns radio / SIM ops; the local controller owns
7
7
  // recovery + usage policy. The ModemManagerPort has NO bearer / connect verb —
8
8
  // enforced at build time by forbidden-surface.test.ts.
9
-
10
- export * from './modem-manager';
11
- export * from './network-manager';
12
- export * from './observation';
13
- export * from './ops';
14
- export * from './receipts';
15
- export * from './reconcile';
16
- export * from './router';
9
+ export * from './location.js';
10
+ export * from './modem-manager.js';
11
+ export * from './mutation-admission.js';
12
+ export * from './network-manager.js';
13
+ export * from './observation.js';
14
+ export * from './ops.js';
15
+ export * from './receipts.js';
16
+ export * from './reconcile.js';
17
+ export * from './resource-ownership.js';
18
+ export * from './router.js';
19
+ export * from './sms.js';
20
+ export * from './uhubctl.js';
@@ -0,0 +1,87 @@
1
+ import type { EpochMillis } from '../domain/index.js';
2
+ import type { ModemRef } from './modem-manager.js';
3
+ /**
4
+ * The GNSS sources `Modem.Location.Capabilities` can advertise, as decoded source
5
+ * names. `3gpp-lac-ci` is deliberately absent: coarse cell location is the cell-info
6
+ * module's surface, and MM advertises it on devices with no GNSS receiver at all.
7
+ */
8
+ export declare const GNSS_SOURCES: readonly ["gps-raw", "gps-nmea", "gps-unmanaged", "agps-msa", "agps-msb"];
9
+ export type GnssSource = (typeof GNSS_SOURCES)[number];
10
+ /** What `Modem.Location` advertises and what is switched on right now. */
11
+ export interface LocationStatus {
12
+ /** Every source name in `Capabilities`, GNSS or not (`3gpp-lac-ci` included). */
13
+ readonly capabilities: ReadonlySet<string>;
14
+ /** Every source name in `Enabled`. */
15
+ readonly enabledSources: ReadonlySet<string>;
16
+ /** True when at least one GNSS source is advertised. */
17
+ readonly gnssCapable: boolean;
18
+ /** True when at least one GNSS source is switched on. */
19
+ readonly gnssEnabled: boolean;
20
+ }
21
+ export type LocationStatusResult = {
22
+ readonly ok: true;
23
+ readonly status: LocationStatus;
24
+ } | {
25
+ readonly ok: false;
26
+ readonly reason: string;
27
+ };
28
+ /**
29
+ * One GNSS fix. SENSITIVE: never persist it, never upload it, never put it in a log
30
+ * line. `observedAt` is when this process READ the fix, which is what staleness is
31
+ * measured against — a modem's own `utc-time` cannot be trusted to advance.
32
+ */
33
+ export interface GnssFix {
34
+ readonly latitude: number;
35
+ readonly longitude: number;
36
+ readonly altitude?: number;
37
+ readonly utcTime?: string;
38
+ readonly observedAt: EpochMillis;
39
+ }
40
+ /**
41
+ * The outcome of ONE read attempt. `no-fix` is a first-class success: the modem
42
+ * answered and has not acquired a position. It is never conflated with an error and
43
+ * never answered with a previous fix — a stale coordinate rendered as current is the
44
+ * one failure mode this module exists to prevent.
45
+ */
46
+ export type FixRead = {
47
+ readonly outcome: 'fix';
48
+ readonly fix: GnssFix;
49
+ } | {
50
+ readonly outcome: 'no-fix';
51
+ readonly reason: string;
52
+ } | {
53
+ readonly outcome: 'disabled';
54
+ readonly reason: string;
55
+ } | {
56
+ readonly outcome: 'unsupported';
57
+ readonly reason: string;
58
+ } | {
59
+ readonly outcome: 'error';
60
+ readonly reason: string;
61
+ };
62
+ /**
63
+ * The outcome of switching GNSS on or off. Modelled like `SimUnlockResult` rather
64
+ * than as a reconcile `Receipt`: GNSS is an operator-invoked, gate-defaulted-off
65
+ * action with no desired-state dimension, so it is not something the planner
66
+ * converges.
67
+ */
68
+ export interface LocationToggleResult {
69
+ readonly outcome: 'applied' | 'unsupported' | 'failed';
70
+ readonly reason: string;
71
+ /** The GNSS sources enabled after the call — empty after a successful disable. */
72
+ readonly enabledSources: ReadonlySet<string>;
73
+ }
74
+ /**
75
+ * Read GNSS status, switch GNSS on/off, and read the current fix.
76
+ *
77
+ * Deliberately NOT part of `ModemManagerPort`: a consumer that only reconciles
78
+ * radio and SIM state has no business holding a handle that can read a position.
79
+ */
80
+ export interface ModemLocationPort {
81
+ getLocationStatus(modem: ModemRef): Promise<LocationStatusResult>;
82
+ enableGnss(modem: ModemRef, sources: readonly GnssSource[]): Promise<LocationToggleResult>;
83
+ disableGnss(modem: ModemRef): Promise<LocationToggleResult>;
84
+ readFix(modem: ModemRef): Promise<FixRead>;
85
+ }
86
+ export declare function isGnssSource(value: string): value is GnssSource;
87
+ export declare function hasGnssSource(sources: Iterable<string>): boolean;
@@ -0,0 +1,36 @@
1
+ // The GNSS location port — ModemManager's `Modem.Location` interface, scoped by a
2
+ // privacy fence that is a PRODUCT rule, not a phase limitation.
3
+ //
4
+ // THE FENCE: this port reads the CURRENT fix and nothing else. There is no history
5
+ // verb, no track verb, no export verb, and no upload verb, and none may ever be
6
+ // added — a fix is held in memory for a live display and is gone the moment GNSS is
7
+ // disabled or the fix goes stale. `location-fence.test.ts` fails the build if a
8
+ // member whose name implies history, tracking, persistence, or upload appears here.
9
+ //
10
+ // A fix also carries coordinates, which say where the operator physically is. That
11
+ // class is redacted by `../redact` (`latitude` / `longitude` / `altitude` / `nmea`),
12
+ // so a fix that reaches a log line or a receipt comes out as the redaction marker
13
+ // rather than a position.
14
+ /**
15
+ * The GNSS sources `Modem.Location.Capabilities` can advertise, as decoded source
16
+ * names. `3gpp-lac-ci` is deliberately absent: coarse cell location is the cell-info
17
+ * module's surface, and MM advertises it on devices with no GNSS receiver at all.
18
+ */
19
+ export const GNSS_SOURCES = [
20
+ 'gps-raw',
21
+ 'gps-nmea',
22
+ 'gps-unmanaged',
23
+ 'agps-msa',
24
+ 'agps-msb',
25
+ ];
26
+ export function isGnssSource(value) {
27
+ return GNSS_SOURCES.includes(value);
28
+ }
29
+ export function hasGnssSource(sources) {
30
+ for (const source of sources) {
31
+ if (isGnssSource(source)) {
32
+ return true;
33
+ }
34
+ }
35
+ return false;
36
+ }
@@ -0,0 +1,89 @@
1
+ import type { DesiredRadio, EpochMillis, RuntimePath } from '../domain/index.js';
2
+ import type { ModemObservationPort } from './observation.js';
3
+ import type { Receipt } from './receipts.js';
4
+ /** A live handle to one modem — its ModemManager D-Bus object path (per-boot). */
5
+ export type ModemRef = RuntimePath;
6
+ /** Outcome of a SIM PIN unlock attempt. */
7
+ export interface SimUnlockResult {
8
+ readonly outcome: 'unlocked' | 'incorrect-pin' | 'sim-puk-required' | 'unsupported' | 'error';
9
+ readonly remainingAttempts?: number;
10
+ readonly reason: string;
11
+ }
12
+ /** Outcome of a SIM PUK unblock attempt. */
13
+ export interface SimPukUnlockResult {
14
+ readonly outcome: 'unlocked' | 'incorrect-puk' | 'permanently-blocked' | 'unsupported' | 'error';
15
+ readonly remainingAttempts?: number;
16
+ readonly reason: string;
17
+ }
18
+ /** One operator returned by a network scan. */
19
+ export interface ScannedNetwork {
20
+ /** MCC+MNC operator code. */
21
+ readonly operatorCode: string;
22
+ readonly operatorName?: string;
23
+ readonly availability: 'available' | 'current' | 'forbidden' | 'unknown';
24
+ }
25
+ /** Result of a network scan — discriminated, retaining the reason on failure. */
26
+ export type NetworkScanResult = {
27
+ readonly ok: true;
28
+ readonly networks: readonly ScannedNetwork[];
29
+ } | {
30
+ readonly ok: false;
31
+ readonly reason: string;
32
+ };
33
+ /**
34
+ * What a modem says about its bands, right now.
35
+ *
36
+ * `supported` and `current` are BOTH required, and both may legitimately be
37
+ * empty: a modem that advertises no band control answers an empty `supported`,
38
+ * which is a real reading and the thing that keeps a control from being offered.
39
+ * A read that could not happen at all is the `ok: false` arm instead — the same
40
+ * "unknown is an answer about the READ" split the capability probes follow.
41
+ */
42
+ export interface ModemBands {
43
+ readonly supported: readonly string[];
44
+ readonly current: readonly string[];
45
+ }
46
+ export type BandReadResult = {
47
+ readonly ok: true;
48
+ readonly bands: ModemBands;
49
+ } | {
50
+ readonly ok: false;
51
+ readonly reason: string;
52
+ };
53
+ /** A held inhibition over a modem, released via `uninhibit`. */
54
+ export interface InhibitLease {
55
+ /** The equipment UID the inhibition is keyed to. */
56
+ readonly uid: string;
57
+ readonly acquiredAt: EpochMillis;
58
+ }
59
+ /**
60
+ * The ModemManager port — EXTENDS the read-only observation port with the modem
61
+ * mutations MM legitimately owns: radio modes, primary SIM slot, PIN / PUK unlock,
62
+ * network scan, and inhibit / uninhibit. It owns NO bearer / connection lifecycle;
63
+ * bearers and activation belong to `NetworkManagerPort`.
64
+ */
65
+ export interface ModemManagerInhibitPort {
66
+ /** Inhibit MM from managing a device (for a maintenance lease), keyed by UID. */
67
+ inhibit(uid: string): Promise<InhibitLease>;
68
+ /** Release a previously-taken inhibition. */
69
+ uninhibit(lease: InhibitLease): Promise<void>;
70
+ }
71
+ export interface ModemManagerPort extends ModemObservationPort, ModemManagerInhibitPort {
72
+ /** Set the modem's radio access-technology preference. */
73
+ setRadioModes(modem: ModemRef, preference: DesiredRadio): Promise<Receipt>;
74
+ /** Read the modem's supported and currently-selected bands. */
75
+ readBands(modem: ModemRef): Promise<BandReadResult>;
76
+ /**
77
+ * Lock the modem to a band selection. Passing exactly `['any']` releases the
78
+ * lock — ModemManager has no separate reset verb, so this IS the reset.
79
+ */
80
+ setCurrentBands(modem: ModemRef, bands: readonly string[]): Promise<Receipt>;
81
+ /** Select the primary SIM slot (multi-slot modems only). */
82
+ setPrimarySimSlot(modem: ModemRef, slotIndex: number): Promise<Receipt>;
83
+ /** Submit a SIM PIN (exactly-once; read-before-submit is the adapter's job). */
84
+ sendPin(modem: ModemRef, pin: string): Promise<SimUnlockResult>;
85
+ /** Submit a SIM PUK plus the new PIN (exactly-once). */
86
+ sendPuk(modem: ModemRef, puk: string, newPin: string): Promise<SimPukUnlockResult>;
87
+ /** Scan for visible networks (long-running). */
88
+ scanNetworks(modem: ModemRef): Promise<NetworkScanResult>;
89
+ }
@@ -0,0 +1,9 @@
1
+ // The ModemManager port — radio, SIM, scan, inhibit, and observation.
2
+ //
3
+ // CRITICAL INVARIANT (the single most safety-critical constraint in the package):
4
+ // this port has NO bearer / connection verb. There is no connect, no createBearer,
5
+ // no bearerConnect — MM's Simple.Connect / CreateBearer / Bearer.Connect are NEVER
6
+ // callable through here. NetworkManager is the sole owner of bearers and activation
7
+ // (see README ownership table). `forbidden-surface.test.ts` fails the build if any
8
+ // such method is ever added to this file.
9
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { MutationImpact, OperationRequirement, PhysicalModemId } from '../domain/index.js';
2
+ export type MutationAdmissionRequest = {
3
+ readonly operationId: string;
4
+ readonly physicalModemId: PhysicalModemId;
5
+ readonly impact: MutationImpact;
6
+ readonly requirement: OperationRequirement;
7
+ };
8
+ export interface MutationAdmissionLease {
9
+ release(): Promise<void>;
10
+ }
11
+ export type MutationAdmissionRefusalReason = 'admission-port-missing' | 'admission-refused';
12
+ export type MutationAdmissionDecision = {
13
+ readonly status: 'admitted';
14
+ readonly lease: MutationAdmissionLease;
15
+ } | {
16
+ readonly status: 'refused';
17
+ readonly reason: MutationAdmissionRefusalReason;
18
+ readonly detail?: string;
19
+ };
20
+ export type MutationAdmissionResult = {
21
+ readonly status: 'not-required';
22
+ } | MutationAdmissionDecision;
23
+ /** Consumer-owned admission authority. The package neither derives nor interprets its policy. */
24
+ export interface MutationAdmissionPort {
25
+ acquire(request: MutationAdmissionRequest): Promise<MutationAdmissionDecision>;
26
+ }
27
+ export declare function acquireMutationAdmission(request: MutationAdmissionRequest, port: MutationAdmissionPort | undefined): Promise<MutationAdmissionResult>;
@@ -0,0 +1,9 @@
1
+ export function acquireMutationAdmission(request, port) {
2
+ if (!request.requirement.required) {
3
+ return Promise.resolve({ status: 'not-required' });
4
+ }
5
+ if (port === undefined) {
6
+ return Promise.resolve({ status: 'refused', reason: 'admission-port-missing' });
7
+ }
8
+ return port.acquire(request);
9
+ }