@ceralive/modem-control 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +341 -0
  2. package/dist/backend/at-lease.d.ts +59 -0
  3. package/dist/backend/at-lease.js +118 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +101 -0
  61. package/dist/backend/transition-preconditions.js +132 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +216 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +20 -0
  146. package/dist/index.js +27 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +61 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operation-ids.d.ts +2 -0
  196. package/dist/operation-ids.js +26 -0
  197. package/dist/operations/contracts.d.ts +72 -0
  198. package/dist/operations/contracts.js +1 -0
  199. package/dist/operations/index.d.ts +1 -0
  200. package/dist/operations/index.js +1 -0
  201. package/dist/operations/operation-engine.d.ts +16 -0
  202. package/dist/operations/operation-engine.js +194 -0
  203. package/dist/ports/index.d.ts +12 -0
  204. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  205. package/dist/ports/location.d.ts +87 -0
  206. package/dist/ports/location.js +36 -0
  207. package/dist/ports/modem-manager.d.ts +89 -0
  208. package/dist/ports/modem-manager.js +9 -0
  209. package/dist/ports/mutation-admission.d.ts +27 -0
  210. package/dist/ports/mutation-admission.js +9 -0
  211. package/dist/ports/network-manager.d.ts +68 -0
  212. package/dist/ports/network-manager.js +13 -0
  213. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  214. package/dist/ports/observation.js +7 -0
  215. package/dist/ports/ops.d.ts +44 -0
  216. package/dist/ports/ops.js +16 -0
  217. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  218. package/dist/ports/receipts.js +9 -0
  219. package/dist/ports/reconcile.d.ts +33 -0
  220. package/dist/ports/reconcile.js +200 -0
  221. package/dist/ports/resource-ownership.d.ts +29 -0
  222. package/dist/ports/resource-ownership.js +1 -0
  223. package/dist/ports/router.d.ts +19 -0
  224. package/dist/ports/router.js +7 -0
  225. package/dist/ports/sms.d.ts +64 -0
  226. package/dist/ports/sms.js +24 -0
  227. package/dist/ports/uhubctl.d.ts +6 -0
  228. package/dist/ports/uhubctl.js +1 -0
  229. package/dist/providers/contracts.d.ts +124 -0
  230. package/dist/providers/contracts.js +10 -0
  231. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  232. package/dist/providers/huawei-hilink/index.js +2 -0
  233. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  234. package/dist/providers/huawei-hilink/operations.js +56 -0
  235. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  236. package/dist/providers/huawei-hilink/provider.js +76 -0
  237. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  238. package/dist/providers/huawei-hilink/runtime.js +171 -0
  239. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  240. package/dist/providers/huawei-hilink/session.js +120 -0
  241. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  242. package/dist/providers/huawei-hilink/transport.js +1 -0
  243. package/dist/providers/index.d.ts +8 -0
  244. package/dist/providers/index.js +8 -0
  245. package/dist/providers/matcher.d.ts +3 -0
  246. package/dist/providers/matcher.js +205 -0
  247. package/dist/providers/modem-manager/errors.d.ts +7 -0
  248. package/dist/providers/modem-manager/errors.js +37 -0
  249. package/dist/providers/modem-manager/generic-operations.d.ts +10 -0
  250. package/dist/providers/modem-manager/generic-operations.js +209 -0
  251. package/dist/providers/modem-manager/index.d.ts +4 -0
  252. package/dist/providers/modem-manager/index.js +4 -0
  253. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  254. package/dist/providers/modem-manager/module-operations.js +118 -0
  255. package/dist/providers/modem-manager/provider.d.ts +41 -0
  256. package/dist/providers/modem-manager/provider.js +155 -0
  257. package/dist/providers/modem-manager/runtime-composition-operation.d.ts +32 -0
  258. package/dist/providers/modem-manager/runtime-composition-operation.js +151 -0
  259. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  260. package/dist/providers/modem-manager/snapshot.js +204 -0
  261. package/dist/providers/modem-manager/types.d.ts +137 -0
  262. package/dist/providers/modem-manager/types.js +1 -0
  263. package/dist/providers/network-manager/adapter.d.ts +71 -0
  264. package/dist/providers/network-manager/adapter.js +348 -0
  265. package/dist/providers/network-manager/index.d.ts +2 -0
  266. package/dist/providers/network-manager/index.js +2 -0
  267. package/dist/providers/network-manager/types.d.ts +171 -0
  268. package/dist/providers/network-manager/types.js +77 -0
  269. package/dist/providers/registry.d.ts +13 -0
  270. package/dist/providers/registry.js +33 -0
  271. package/dist/providers/ufi-himi/index.d.ts +6 -0
  272. package/dist/providers/ufi-himi/index.js +6 -0
  273. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  274. package/dist/providers/ufi-himi/operations.js +66 -0
  275. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  276. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  277. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  278. package/dist/providers/ufi-himi/provider.js +204 -0
  279. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  280. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  281. package/dist/providers/ufi-himi/session.d.ts +46 -0
  282. package/dist/providers/ufi-himi/session.js +92 -0
  283. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  284. package/dist/providers/ufi-himi/transport.js +25 -0
  285. package/dist/providers/zte-goform/index.d.ts +2 -0
  286. package/dist/providers/zte-goform/index.js +2 -0
  287. package/dist/providers/zte-goform/provider.d.ts +56 -0
  288. package/dist/providers/zte-goform/provider.js +101 -0
  289. package/dist/providers/zte-goform/session.d.ts +23 -0
  290. package/dist/providers/zte-goform/session.js +197 -0
  291. package/dist/providers/zte-goform/transport.d.ts +16 -0
  292. package/dist/providers/zte-goform/transport.js +1 -0
  293. package/dist/radio/band-truth.d.ts +50 -0
  294. package/dist/radio/band-truth.js +92 -0
  295. package/dist/radio/index.d.ts +3 -0
  296. package/dist/radio/index.js +10 -0
  297. package/dist/radio/mode-combinations.d.ts +88 -0
  298. package/dist/radio/mode-combinations.js +198 -0
  299. package/dist/radio/mode-truth.d.ts +67 -0
  300. package/dist/radio/mode-truth.js +112 -0
  301. package/dist/redact.d.ts +15 -0
  302. package/dist/redact.js +189 -0
  303. package/dist/safety/composition-root.d.ts +28 -0
  304. package/dist/safety/composition-root.js +65 -0
  305. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  306. package/dist/safety/flock-resource-ownership.js +138 -0
  307. package/dist/safety/index.d.ts +2 -0
  308. package/dist/safety/index.js +2 -0
  309. package/dist/sms/dbus-messaging.d.ts +17 -0
  310. package/dist/sms/dbus-messaging.js +185 -0
  311. package/dist/sms/inbox-store.d.ts +10 -0
  312. package/dist/sms/inbox-store.js +82 -0
  313. package/dist/sms/index.d.ts +4 -0
  314. package/dist/sms/index.js +10 -0
  315. package/dist/sms/mmcli-parse.d.ts +54 -0
  316. package/dist/sms/mmcli-parse.js +224 -0
  317. package/dist/sms/normalize.d.ts +42 -0
  318. package/dist/sms/normalize.js +95 -0
  319. package/dist/testing/domain-fakes.d.ts +58 -0
  320. package/dist/testing/domain-fakes.js +98 -0
  321. package/dist/testing/index.d.ts +2 -0
  322. package/dist/testing/index.js +17 -0
  323. package/dist/testing/provider-fakes.d.ts +45 -0
  324. package/dist/testing/provider-fakes.js +64 -0
  325. package/dist/transport/calls.d.ts +9 -0
  326. package/dist/transport/calls.js +88 -0
  327. package/dist/transport/codec.d.ts +3 -0
  328. package/dist/transport/codec.js +207 -0
  329. package/dist/transport/dbus-native.d.ts +57 -0
  330. package/dist/transport/dbus-native.js +17 -0
  331. package/dist/transport/errors.d.ts +21 -0
  332. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  333. package/dist/transport/index.d.ts +4 -0
  334. package/dist/transport/index.js +9 -0
  335. package/dist/transport/signals.d.ts +15 -0
  336. package/dist/transport/signals.js +123 -0
  337. package/dist/transport/signature.d.ts +7 -0
  338. package/dist/transport/signature.js +94 -0
  339. package/dist/transport/transport.d.ts +2 -0
  340. package/dist/transport/transport.js +202 -0
  341. package/dist/transport/types.d.ts +61 -0
  342. package/dist/transport/types.js +19 -0
  343. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  344. package/dist/usb-mode/catalog-schema.js +97 -0
  345. package/dist/usb-mode/catalog.d.ts +21 -0
  346. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  347. package/dist/usb-mode/certified-catalog.json +67 -0
  348. package/dist/usb-mode/index.d.ts +6 -0
  349. package/dist/usb-mode/index.js +16 -0
  350. package/dist/usb-mode/ingestion.d.ts +111 -0
  351. package/dist/usb-mode/ingestion.js +187 -0
  352. package/dist/usb-mode/promotion-review.d.ts +21 -0
  353. package/dist/usb-mode/promotion-review.js +87 -0
  354. package/dist/usb-mode/runtime-capability.d.ts +59 -0
  355. package/dist/usb-mode/runtime-capability.js +157 -0
  356. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  357. package/dist/usb-mode/usb-devices-parse.js +157 -0
  358. package/dist/ussd/calls.d.ts +32 -0
  359. package/dist/ussd/calls.js +96 -0
  360. package/dist/ussd/index.d.ts +5 -0
  361. package/dist/ussd/index.js +12 -0
  362. package/dist/ussd/mm-ussd.d.ts +37 -0
  363. package/dist/ussd/mm-ussd.js +205 -0
  364. package/dist/ussd/refusal.d.ts +53 -0
  365. package/dist/ussd/refusal.js +154 -0
  366. package/dist/ussd/registration.d.ts +20 -0
  367. package/dist/ussd/registration.js +101 -0
  368. package/dist/ussd/session.d.ts +106 -0
  369. package/dist/ussd/session.js +163 -0
  370. package/package.json +38 -4
  371. package/src/backend/at-lease.test.ts +0 -106
  372. package/src/backend/at-lease.ts +0 -158
  373. package/src/backend/cell-info.test.ts +0 -154
  374. package/src/backend/cell-info.ts +0 -160
  375. package/src/backend/device-classifier.test.ts +0 -168
  376. package/src/backend/device-classifier.ts +0 -248
  377. package/src/backend/enrichment.ts +0 -96
  378. package/src/backend/features.test.ts +0 -162
  379. package/src/backend/features.ts +0 -179
  380. package/src/backend/identity-ladder.test.ts +0 -117
  381. package/src/backend/identity-ladder.ts +0 -221
  382. package/src/backend/identity-registry.test.ts +0 -89
  383. package/src/backend/identity-registry.ts +0 -151
  384. package/src/backend/index.ts +0 -236
  385. package/src/backend/lifecycle-interlock.ts +0 -38
  386. package/src/backend/managed-objects.ts +0 -108
  387. package/src/backend/mapping.ts +0 -160
  388. package/src/backend/mm-backend.ts +0 -191
  389. package/src/backend/mm-mutations.ts +0 -228
  390. package/src/backend/modem-actor.test.ts +0 -95
  391. package/src/backend/modem-actor.ts +0 -112
  392. package/src/backend/nm-auto-apn.ts +0 -161
  393. package/src/backend/nm-gsm-fields.ts +0 -122
  394. package/src/backend/nmcli-nm-port.ts +0 -228
  395. package/src/backend/nmcli-runner.ts +0 -52
  396. package/src/backend/observer.ts +0 -297
  397. package/src/backend/power-contract.test.ts +0 -40
  398. package/src/backend/power-contract.ts +0 -83
  399. package/src/backend/recovery-attribution.test.ts +0 -102
  400. package/src/backend/recovery-attribution.ts +0 -86
  401. package/src/backend/recovery-budget.test.ts +0 -64
  402. package/src/backend/recovery-budget.ts +0 -84
  403. package/src/backend/recovery-ladder.test.ts +0 -257
  404. package/src/backend/recovery-ladder.ts +0 -249
  405. package/src/backend/router-ethernet.test.ts +0 -71
  406. package/src/backend/router-ethernet.ts +0 -90
  407. package/src/backend/row-store.ts +0 -105
  408. package/src/backend/signal-setup.ts +0 -112
  409. package/src/backend/sim-unlock.ts +0 -193
  410. package/src/backend/transition-preconditions.ts +0 -149
  411. package/src/backend/uhubctl-power-hook.test.ts +0 -274
  412. package/src/backend/uhubctl-power-hook.ts +0 -377
  413. package/src/backend/usage/accounting.test.ts +0 -147
  414. package/src/backend/usage/accounting.ts +0 -123
  415. package/src/backend/usage/billing-cycle.test.ts +0 -62
  416. package/src/backend/usage/billing-cycle.ts +0 -45
  417. package/src/backend/usage/index.ts +0 -60
  418. package/src/backend/usage/policy-store.test.ts +0 -164
  419. package/src/backend/usage/policy-store.ts +0 -216
  420. package/src/backend/usage/policy-write.test.ts +0 -198
  421. package/src/backend/usage/policy-write.ts +0 -207
  422. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  423. package/src/backend/usage/sampler.test.ts +0 -327
  424. package/src/backend/usage/sampler.ts +0 -282
  425. package/src/backend/usage/store.test.ts +0 -148
  426. package/src/backend/usage/store.ts +0 -177
  427. package/src/backend/usb-enumerator.test.ts +0 -87
  428. package/src/backend/usb-enumerator.ts +0 -181
  429. package/src/backend/usb-mode-transition.test.ts +0 -323
  430. package/src/backend/usb-mode-transition.ts +0 -253
  431. package/src/domain/brand.ts +0 -29
  432. package/src/domain/errors.ts +0 -77
  433. package/src/domain/guards.test.ts +0 -218
  434. package/src/domain/guards.ts +0 -144
  435. package/src/domain/identity.test.ts +0 -83
  436. package/src/domain/identity.ts +0 -165
  437. package/src/domain/index.ts +0 -12
  438. package/src/domain/snapshot.test.ts +0 -266
  439. package/src/domain/snapshot.ts +0 -120
  440. package/src/index.test.ts +0 -6
  441. package/src/index.ts +0 -15
  442. package/src/ports/README.md +0 -61
  443. package/src/ports/forbidden-surface.test.ts +0 -241
  444. package/src/ports/modem-manager.ts +0 -72
  445. package/src/ports/network-manager.ts +0 -87
  446. package/src/ports/ops.ts +0 -60
  447. package/src/ports/ops.type-test.ts +0 -39
  448. package/src/ports/receipts.test.ts +0 -153
  449. package/src/ports/reconcile.test.ts +0 -152
  450. package/src/ports/reconcile.ts +0 -338
  451. package/src/ports/router.ts +0 -29
  452. package/src/redact.test.ts +0 -82
  453. package/src/redact.ts +0 -73
  454. package/src/transport/README.md +0 -65
  455. package/src/transport/calls.ts +0 -113
  456. package/src/transport/characterization.test.ts +0 -260
  457. package/src/transport/codec.test.ts +0 -118
  458. package/src/transport/codec.ts +0 -240
  459. package/src/transport/conformance-python.test.ts +0 -152
  460. package/src/transport/conformance-same-lib.test.ts +0 -115
  461. package/src/transport/dbus-native-lib.d.ts +0 -19
  462. package/src/transport/dbus-native.ts +0 -85
  463. package/src/transport/index.ts +0 -30
  464. package/src/transport/no-library-leak.test.ts +0 -61
  465. package/src/transport/reliability.test.ts +0 -173
  466. package/src/transport/signals.ts +0 -150
  467. package/src/transport/signature.ts +0 -110
  468. package/src/transport/test-support/fake-service.ts +0 -168
  469. package/src/transport/test-support/independent-producer.py +0 -110
  470. package/src/transport/test-support/private-bus.ts +0 -66
  471. package/src/transport/transport.ts +0 -250
  472. package/src/transport/types.ts +0 -118
  473. package/src/usb-mode/catalog-schema.test.ts +0 -181
  474. package/src/usb-mode/catalog-schema.ts +0 -113
  475. package/src/usb-mode/certified-catalog.json +0 -67
  476. package/src/usb-mode/index.ts +0 -58
  477. package/src/usb-mode/ingestion.test.ts +0 -268
  478. package/src/usb-mode/ingestion.ts +0 -297
  479. package/src/usb-mode/promotion-review.ts +0 -117
  480. package/src/usb-mode/usb-devices-parse.ts +0 -196
@@ -0,0 +1,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
+ }
@@ -0,0 +1,68 @@
1
+ import type { Brand, EpochMillis } from '../domain/index.js';
2
+ import type { Receipt } from './receipts.js';
3
+ /** A NetworkManager connection-profile UUID. */
4
+ export type ConnectionId = Brand<string, 'ConnectionId'>;
5
+ /** A kernel network-device interface name (e.g. `wwan0`). */
6
+ export type DeviceIfname = Brand<string, 'DeviceIfname'>;
7
+ /** Construct a `ConnectionId` from a non-empty NM connection UUID. */
8
+ export declare function connectionId(value: string): ConnectionId;
9
+ /** Construct a `DeviceIfname` from a non-empty interface name. */
10
+ export declare function deviceIfname(value: string): DeviceIfname;
11
+ /**
12
+ * A GSM connection profile — NM's `gsm.*` setting group. `password` is SENSITIVE
13
+ * and MUST be redacted in every log / output (see `../redact`). The full nine-field
14
+ * nmcli write parity lands with the concrete adapter (A4.1); this is the port
15
+ * contract that adapter fulfils.
16
+ */
17
+ export interface GsmProfileInput {
18
+ readonly connectionName: string;
19
+ /** Concrete APN, or the empty string when `autoConfig` drives it (A4.1). */
20
+ readonly apn: string;
21
+ readonly username?: string;
22
+ /** SENSITIVE — redact everywhere. */
23
+ readonly password?: string;
24
+ /** `true` ⇒ `gsm.home-only` (roaming disabled). */
25
+ readonly homeOnly: boolean;
26
+ /** `true` ⇒ `gsm.auto-config yes` (Auto-APN); mutually exclusive with creds. */
27
+ readonly autoConfig: boolean;
28
+ /** Manual operator selection (`gsm.network-id`); empty unless roaming-pinned. */
29
+ readonly networkId?: string;
30
+ }
31
+ /** A persisted GSM profile as read back from NM, keyed by its connection id. */
32
+ export interface GsmProfile extends GsmProfileInput {
33
+ readonly connectionId: ConnectionId;
34
+ }
35
+ /** A partial update to an existing GSM profile. */
36
+ export type GsmProfilePatch = Partial<GsmProfileInput>;
37
+ /**
38
+ * A quiesce lease — a held guarantee that the connection on THIS exact device stays
39
+ * deactivated while a disruptive MM operation runs, then is reactivated on release.
40
+ * Bound to BOTH `connectionId` and `deviceIfname` so it can never quiesce the wrong
41
+ * device (the two-device isolation invariant, A4.1).
42
+ */
43
+ export interface QuiesceLease {
44
+ readonly connectionId: ConnectionId;
45
+ readonly deviceIfname: DeviceIfname;
46
+ readonly acquiredAt: EpochMillis;
47
+ }
48
+ /**
49
+ * The NetworkManager port. Activation and deactivation take BOTH the connection id
50
+ * AND the device interface name — never an id alone. This encodes, at the type
51
+ * level, that we address a connection on an EXACT device (`nmcli connection up
52
+ * <uuid> ifname <dev>` / verify-then-`device disconnect <ifname>`); the id-only
53
+ * `nmcli connection down` is structurally impossible to express here (A4.1).
54
+ */
55
+ export interface NetworkManagerPort {
56
+ createGsmProfile(profile: GsmProfileInput): Promise<GsmProfile>;
57
+ readGsmProfile(id: ConnectionId): Promise<GsmProfile | undefined>;
58
+ updateGsmProfile(id: ConnectionId, patch: GsmProfilePatch): Promise<GsmProfile>;
59
+ deleteGsmProfile(id: ConnectionId): Promise<void>;
60
+ /** Activate `id` on the EXACT device `ifname`. */
61
+ activate(id: ConnectionId, ifname: DeviceIfname): Promise<Receipt>;
62
+ /** Deactivate `id` on the EXACT device `ifname`. */
63
+ deactivate(id: ConnectionId, ifname: DeviceIfname): Promise<Receipt>;
64
+ /** Take a quiesce lease over `id` on the EXACT device `ifname`. */
65
+ acquireQuiesceLease(id: ConnectionId, ifname: DeviceIfname): Promise<QuiesceLease>;
66
+ /** Release a quiesce lease, reactivating the connection it held down. */
67
+ releaseQuiesceLease(lease: QuiesceLease): Promise<void>;
68
+ }
@@ -0,0 +1,13 @@
1
+ // The NetworkManager port — NM is the SOLE owner of bearers, APN, auth, roaming,
2
+ // autoconnect, and activation (see README ownership table). This port is the ONLY
3
+ // way the controller touches any of those resources; the ModemManager port has no
4
+ // bearer / connection verbs at all.
5
+ import { nonEmptyString } from '../domain/index.js';
6
+ /** Construct a `ConnectionId` from a non-empty NM connection UUID. */
7
+ export function connectionId(value) {
8
+ return nonEmptyString(value, 'connectionId');
9
+ }
10
+ /** Construct a `DeviceIfname` from a non-empty interface name. */
11
+ export function deviceIfname(value) {
12
+ return nonEmptyString(value, 'deviceIfname');
13
+ }
@@ -1,18 +1,8 @@
1
- // The observation contract the read side shared by every ModemManager backend.
2
- //
3
- // `ModemObservationPort` is the NARROW port: it observes modems and reports them as
4
- // a stream of discriminated list results. It carries NO mutation methods at all.
5
- // The full `ModemManagerPort` (mutations) EXTENDS this, so a shadow / read-only
6
- // consumer can depend on observation alone and never gain a mutating verb.
7
-
8
- import type { CellularSnapshot } from '../domain';
9
-
1
+ import type { CellularSnapshot } from '../domain/index.js';
10
2
  /** Cancels a subscription created by `observe`. Calling it twice is a no-op. */
11
3
  export type Unsubscribe = () => void;
12
-
13
4
  /** Why an observation could not produce an authoritative list this cycle. */
14
5
  export type ObservationFailureReason = 'not-started' | 'source-unavailable' | 'bus-error';
15
-
16
6
  /**
17
7
  * The result of listing modems — DISCRIMINATED on `ok`, and it NEVER throws away
18
8
  * rows. Even the failure arm carries `rows`: the last-known modems are RETAINED so
@@ -20,18 +10,17 @@ export type ObservationFailureReason = 'not-started' | 'source-unavailable' | 'b
20
10
  * expressed by an `ok: true` snapshot that OMITS a modem (A3.1 epoch authority) —
21
11
  * the false-removal class is dead by construction.
22
12
  */
23
- export type ObservationList<T = CellularSnapshot> =
24
- | { readonly ok: true; readonly rows: readonly T[] }
25
- | {
26
- readonly ok: false;
27
- readonly reason: ObservationFailureReason;
28
- /** Retained rows from the last authoritative snapshot — never dropped. */
29
- readonly rows: readonly T[];
30
- };
31
-
13
+ export type ObservationList<T = CellularSnapshot> = {
14
+ readonly ok: true;
15
+ readonly rows: readonly T[];
16
+ } | {
17
+ readonly ok: false;
18
+ readonly reason: ObservationFailureReason;
19
+ /** Retained rows from the last authoritative snapshot — never dropped. */
20
+ readonly rows: readonly T[];
21
+ };
32
22
  /** A subscriber to the ongoing observation stream. */
33
23
  export type ObservationListener<T = CellularSnapshot> = (list: ObservationList<T>) => void;
34
-
35
24
  /**
36
25
  * The read-only observation port. `start()` connects, subscribes, and resolves the
37
26
  * first AUTHORITATIVE list; `observe()` streams every subsequent list (each snapshot
@@ -39,10 +28,10 @@ export type ObservationListener<T = CellularSnapshot> = (list: ObservationList<T
39
28
  * here can change modem state — that narrowness is the whole point of the port.
40
29
  */
41
30
  export interface ModemObservationPort {
42
- /** Connect, subscribe, and resolve the first authoritative observation list. */
43
- start(): Promise<ObservationList>;
44
- /** Subscribe to the ongoing stream of observation lists. Returns an unsubscribe. */
45
- observe(listener: ObservationListener): Unsubscribe;
46
- /** Tear down the subscription and release the source. Idempotent. */
47
- stop(): Promise<void>;
31
+ /** Connect, subscribe, and resolve the first authoritative observation list. */
32
+ start(): Promise<ObservationList>;
33
+ /** Subscribe to the ongoing stream of observation lists. Returns an unsubscribe. */
34
+ observe(listener: ObservationListener): Unsubscribe;
35
+ /** Tear down the subscription and release the source. Idempotent. */
36
+ stop(): Promise<void>;
48
37
  }
@@ -0,0 +1,7 @@
1
+ // The observation contract — the read side shared by every ModemManager backend.
2
+ //
3
+ // `ModemObservationPort` is the NARROW port: it observes modems and reports them as
4
+ // a stream of discriminated list results. It carries NO mutation methods at all.
5
+ // The full `ModemManagerPort` (mutations) EXTENDS this, so a shadow / read-only
6
+ // consumer can depend on observation alone and never gain a mutating verb.
7
+ export {};