@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,39 @@
1
+ import type { Brand } from './brand.js';
2
+ import type { DeviceGeneration } from './generation.js';
3
+ import type { StableKey } from './physical-identity.js';
4
+ import type { EpochMillis } from './state.js';
5
+ export type SourceEpoch = Brand<number, 'SourceEpoch'>;
6
+ export declare function sourceEpoch(value: number): SourceEpoch;
7
+ export type ObservationAuthority = 'authoritative' | 'derived' | 'advisory';
8
+ export type ObservationFreshness = {
9
+ readonly state: 'fresh';
10
+ } | {
11
+ readonly state: 'stale';
12
+ readonly since: EpochMillis;
13
+ readonly reason: 'source-epoch-superseded' | 'ttl-expired' | 'source-degraded';
14
+ } | {
15
+ readonly state: 'unavailable';
16
+ readonly since: EpochMillis;
17
+ readonly reason: 'source-unavailable' | 'device-absent' | 'provider-unavailable';
18
+ };
19
+ type ObservationBase = {
20
+ readonly stableKey: StableKey;
21
+ readonly generation: DeviceGeneration;
22
+ readonly source: string;
23
+ readonly sourceEpoch: SourceEpoch;
24
+ readonly observedAt: EpochMillis;
25
+ readonly authority: ObservationAuthority;
26
+ };
27
+ /** A value is retained while stale, but unavailable is explicit and carries no invented value. */
28
+ export type ObservationEnvelope<T> = (ObservationBase & {
29
+ readonly freshness: Extract<ObservationFreshness, {
30
+ readonly state: 'fresh' | 'stale';
31
+ }>;
32
+ readonly value: T;
33
+ }) | (ObservationBase & {
34
+ readonly freshness: Extract<ObservationFreshness, {
35
+ readonly state: 'unavailable';
36
+ }>;
37
+ readonly value: null;
38
+ });
39
+ export {};
@@ -0,0 +1,4 @@
1
+ import { nonNegativeInteger } from './brand.js';
2
+ export function sourceEpoch(value) {
3
+ return nonNegativeInteger(value, 'sourceEpoch');
4
+ }
@@ -0,0 +1,118 @@
1
+ import { DomainError } from './errors.js';
2
+ import type { DeviceGeneration } from './generation.js';
3
+ export type OperationSupport = {
4
+ readonly supported: true;
5
+ } | {
6
+ readonly supported: false;
7
+ readonly reason: string;
8
+ };
9
+ export type OperationConstraints<I> = {
10
+ readonly kind: 'unconstrained';
11
+ } | {
12
+ readonly kind: 'allowed-values';
13
+ readonly values: readonly I[];
14
+ } | {
15
+ readonly kind: 'numeric-range';
16
+ readonly min: number;
17
+ readonly max: number;
18
+ readonly step?: number;
19
+ };
20
+ export type OperationAvailability = {
21
+ readonly state: 'available';
22
+ } | {
23
+ readonly state: 'unavailable';
24
+ readonly reason: string;
25
+ } | {
26
+ readonly state: 'refused';
27
+ readonly reason: string;
28
+ };
29
+ export type MutationImpact = 'read' | 'write' | 'session' | 'disruptive' | 'recovery';
30
+ export type RetryClass = 'never' | 'idempotent-read';
31
+ export type OperationConfidence = 'high' | 'medium' | 'low' | 'unknown';
32
+ export type OperationRequirement = {
33
+ readonly required: false;
34
+ } | {
35
+ readonly required: true;
36
+ readonly reason: string;
37
+ };
38
+ export type OperationReadback<I, O> = {
39
+ readonly required: false;
40
+ } | {
41
+ readonly required: true;
42
+ readonly reason: string;
43
+ readonly matches: (input: I, observed: O) => boolean;
44
+ };
45
+ export type OperationDescriptor<I, O> = {
46
+ readonly id: string;
47
+ readonly support: {
48
+ readonly read: OperationSupport;
49
+ readonly write: OperationSupport;
50
+ };
51
+ readonly authority: 'provider' | 'controller' | 'hardware';
52
+ readonly provider: string;
53
+ readonly constraints: OperationConstraints<I>;
54
+ readonly livePreconditions: readonly string[];
55
+ readonly availability: OperationAvailability;
56
+ readonly mutationImpact: MutationImpact;
57
+ readonly retryClass: RetryClass;
58
+ readonly readback: OperationReadback<I, O>;
59
+ readonly rollback: OperationRequirement;
60
+ readonly journal: OperationRequirement;
61
+ readonly admission: OperationRequirement;
62
+ readonly evidence: {
63
+ readonly profiles: readonly string[];
64
+ readonly firmware: readonly string[];
65
+ };
66
+ readonly confidence: OperationConfidence;
67
+ };
68
+ export declare class OperationDescriptorError extends DomainError {
69
+ readonly name = "OperationDescriptorError";
70
+ readonly reason = "retry-requires-idempotent-read";
71
+ constructor();
72
+ }
73
+ export declare function defineOperationDescriptor<I, O>(descriptor: OperationDescriptor<I, O>): OperationDescriptor<I, O>;
74
+ export type OperationCompletion<O> = {
75
+ readonly status: 'applied';
76
+ readonly value: O;
77
+ } | {
78
+ readonly status: 'refused';
79
+ readonly reason: string;
80
+ } | {
81
+ readonly status: 'failed';
82
+ readonly reason: string;
83
+ } | {
84
+ readonly status: 'timed-out';
85
+ } | {
86
+ readonly status: 'dropped';
87
+ };
88
+ export type OperationResult<O> = {
89
+ readonly status: 'applied';
90
+ readonly value: O;
91
+ readonly generation: DeviceGeneration;
92
+ readonly requiresReconciliation: false;
93
+ } | {
94
+ readonly status: 'refused';
95
+ readonly reason: string;
96
+ readonly generation: DeviceGeneration;
97
+ readonly requiresReconciliation: false;
98
+ } | {
99
+ readonly status: 'unknown-outcome';
100
+ readonly reason: 'stale-generation' | 'write-reply-timed-out' | 'write-reply-dropped';
101
+ readonly generation: DeviceGeneration;
102
+ readonly requiresReconciliation: true;
103
+ } | {
104
+ readonly status: 'failed';
105
+ readonly reason: string;
106
+ readonly generation: DeviceGeneration;
107
+ readonly requiresReconciliation: false;
108
+ };
109
+ export type OperationCompletionContext<O> = {
110
+ readonly operation: 'read' | 'write';
111
+ readonly completionGeneration: DeviceGeneration;
112
+ readonly currentGeneration: DeviceGeneration;
113
+ readonly completion: OperationCompletion<O>;
114
+ };
115
+ /** Apply generation and write-reply uncertainty before exposing a completion to callers. */
116
+ export declare function classifyOperationCompletion<O>(context: OperationCompletionContext<O>): OperationResult<O>;
117
+ /** Automatic retries are restricted to explicitly classified idempotent reads. */
118
+ export declare function canAutoRetry<I, O>(descriptor: OperationDescriptor<I, O>, result: OperationResult<O>): boolean;
@@ -0,0 +1,85 @@
1
+ import { DomainError } from './errors.js';
2
+ export class OperationDescriptorError extends DomainError {
3
+ name = 'OperationDescriptorError';
4
+ reason = 'retry-requires-idempotent-read';
5
+ constructor() {
6
+ super('operation descriptor refused: automatic retry requires a supported idempotent read');
7
+ }
8
+ }
9
+ export function defineOperationDescriptor(descriptor) {
10
+ if (descriptor.retryClass === 'idempotent-read' &&
11
+ (descriptor.mutationImpact !== 'read' || !descriptor.support.read.supported)) {
12
+ throw new OperationDescriptorError();
13
+ }
14
+ return descriptor;
15
+ }
16
+ /** Apply generation and write-reply uncertainty before exposing a completion to callers. */
17
+ export function classifyOperationCompletion(context) {
18
+ const generation = context.completionGeneration;
19
+ if (generation !== context.currentGeneration) {
20
+ return {
21
+ status: 'unknown-outcome',
22
+ reason: 'stale-generation',
23
+ requiresReconciliation: true,
24
+ generation,
25
+ };
26
+ }
27
+ switch (context.completion.status) {
28
+ case 'applied':
29
+ return {
30
+ status: 'applied',
31
+ value: context.completion.value,
32
+ generation,
33
+ requiresReconciliation: false,
34
+ };
35
+ case 'refused':
36
+ return {
37
+ status: 'refused',
38
+ reason: context.completion.reason,
39
+ generation,
40
+ requiresReconciliation: false,
41
+ };
42
+ case 'failed':
43
+ return {
44
+ status: 'failed',
45
+ reason: context.completion.reason,
46
+ generation,
47
+ requiresReconciliation: false,
48
+ };
49
+ case 'timed-out':
50
+ return context.operation === 'write'
51
+ ? {
52
+ status: 'unknown-outcome',
53
+ reason: 'write-reply-timed-out',
54
+ requiresReconciliation: true,
55
+ generation,
56
+ }
57
+ : {
58
+ status: 'failed',
59
+ reason: 'read-reply-timed-out',
60
+ requiresReconciliation: false,
61
+ generation,
62
+ };
63
+ case 'dropped':
64
+ return context.operation === 'write'
65
+ ? {
66
+ status: 'unknown-outcome',
67
+ reason: 'write-reply-dropped',
68
+ requiresReconciliation: true,
69
+ generation,
70
+ }
71
+ : {
72
+ status: 'failed',
73
+ reason: 'read-reply-dropped',
74
+ requiresReconciliation: false,
75
+ generation,
76
+ };
77
+ }
78
+ }
79
+ /** Automatic retries are restricted to explicitly classified idempotent reads. */
80
+ export function canAutoRetry(descriptor, result) {
81
+ return (descriptor.mutationImpact === 'read' &&
82
+ descriptor.support.read.supported &&
83
+ descriptor.retryClass === 'idempotent-read' &&
84
+ result.status === 'failed');
85
+ }
@@ -0,0 +1,43 @@
1
+ import type { Brand } from './brand.js';
2
+ import { DomainError } from './errors.js';
3
+ export type PhysicalModemId = Brand<string, 'PhysicalModemId'>;
4
+ export type StableKey = Brand<string, 'StableKey'>;
5
+ export type PhysicalIdentitySource = 'serial' | 'id-path' | 'fallback';
6
+ export type PhysicalIdentityFacts = {
7
+ readonly serial?: string;
8
+ readonly idPath?: string;
9
+ readonly fallback?: string;
10
+ };
11
+ export type ResolvedPhysicalModemIdentity = {
12
+ readonly physicalModemId: PhysicalModemId;
13
+ readonly stableKey: StableKey;
14
+ readonly source: PhysicalIdentitySource;
15
+ };
16
+ export type PhysicalModemIdentityErrorReason = 'empty' | 'unsupported-shape' | 'mm-object-path' | 'interface-name' | 'ip-address' | 'equipment-identifier' | 'subscriber-identifier' | 'fallback-too-long' | 'no-identity-facts';
17
+ export declare class PhysicalModemIdentityError extends DomainError {
18
+ readonly reason: PhysicalModemIdentityErrorReason;
19
+ readonly name = "PhysicalModemIdentityError";
20
+ constructor(reason: PhysicalModemIdentityErrorReason);
21
+ }
22
+ /** Construct only from a canonical serial/ID_PATH/bounded-fallback identity. */
23
+ export declare function physicalModemId(value: string): PhysicalModemId;
24
+ /** Construct the actor/storage key for a validated physical modem identity. */
25
+ export declare function stableKeyFromPhysicalModemId(id: PhysicalModemId): StableKey;
26
+ /** Parse a canonical stable key while re-validating its embedded physical identity. */
27
+ export declare function stableKey(value: string): StableKey;
28
+ /** Resolve one identity with the frozen serial → ID_PATH → bounded-fallback precedence. */
29
+ export declare function resolvePhysicalModemIdentity(facts: PhysicalIdentityFacts): ResolvedPhysicalModemIdentity;
30
+ export type PortableIdentityAnchor = 'usb-serial' | 'id-path' | 'ifname';
31
+ export interface PortablePhysicalObservation {
32
+ readonly ifname: string;
33
+ readonly idPath?: string;
34
+ readonly vendorId?: string;
35
+ readonly serial?: string;
36
+ }
37
+ export interface PortablePhysicalDeviceIdentity {
38
+ readonly identityKey: string;
39
+ readonly anchor: PortableIdentityAnchor;
40
+ readonly linkId: string;
41
+ }
42
+ export declare function mintLinkId(identityKey: string): string;
43
+ export declare function resolvePortablePhysicalIdentity(observation: PortablePhysicalObservation): PortablePhysicalDeviceIdentity;
@@ -0,0 +1,113 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { DomainError } from './errors.js';
3
+ export class PhysicalModemIdentityError extends DomainError {
4
+ reason;
5
+ name = 'PhysicalModemIdentityError';
6
+ constructor(reason) {
7
+ super(`physical modem identity refused: ${reason}`);
8
+ this.reason = reason;
9
+ }
10
+ }
11
+ const PHYSICAL_ID_PREFIXES = [
12
+ ['serial', 'serial:'],
13
+ ['id-path', 'id-path:'],
14
+ ['fallback', 'fallback:'],
15
+ ];
16
+ const FALLBACK_MAX_LENGTH = 128;
17
+ const MM_OBJECT_PATH = /^\/org\/freedesktop\/ModemManager1\/Modem(?:\/|$)/;
18
+ const INTERFACE_NAME = /^(?:wwan|eth|enp|ens|eno|wlan|wl|ppp|usb|rmnet|cdc-wdm|ttyUSB|ttyACM)\d[\w.-]*$/i;
19
+ const EQUIPMENT_IDENTIFIER = /^\d{14,16}$/;
20
+ const SUBSCRIBER_IDENTIFIER = /^(?:89\d{16,30}|\d{18,32})$/;
21
+ function isIpv4(value) {
22
+ const octets = value.split('.');
23
+ return (octets.length === 4 && octets.every((octet) => /^\d{1,3}$/.test(octet) && Number(octet) <= 255));
24
+ }
25
+ function isIpv6(value) {
26
+ if (!value.includes(':') || !/^[0-9a-f:]+$/i.test(value)) {
27
+ return false;
28
+ }
29
+ const groups = value.split(':');
30
+ const hasCompression = value.includes('::');
31
+ const populatedGroups = groups.filter((group) => group.length > 0);
32
+ return (populatedGroups.every((group) => group.length <= 4) &&
33
+ (hasCompression ? populatedGroups.length < 8 : populatedGroups.length === 8));
34
+ }
35
+ function assertSafeIdentityPart(value) {
36
+ if (value.length === 0) {
37
+ throw new PhysicalModemIdentityError('empty');
38
+ }
39
+ if (MM_OBJECT_PATH.test(value)) {
40
+ throw new PhysicalModemIdentityError('mm-object-path');
41
+ }
42
+ if (INTERFACE_NAME.test(value)) {
43
+ throw new PhysicalModemIdentityError('interface-name');
44
+ }
45
+ if (isIpv4(value) || isIpv6(value)) {
46
+ throw new PhysicalModemIdentityError('ip-address');
47
+ }
48
+ if (SUBSCRIBER_IDENTIFIER.test(value)) {
49
+ throw new PhysicalModemIdentityError('subscriber-identifier');
50
+ }
51
+ if (EQUIPMENT_IDENTIFIER.test(value)) {
52
+ throw new PhysicalModemIdentityError('equipment-identifier');
53
+ }
54
+ }
55
+ function splitPhysicalModemId(value) {
56
+ for (const [source, prefix] of PHYSICAL_ID_PREFIXES) {
57
+ if (value.startsWith(prefix)) {
58
+ return [source, value.slice(prefix.length)];
59
+ }
60
+ }
61
+ throw new PhysicalModemIdentityError('unsupported-shape');
62
+ }
63
+ /** Construct only from a canonical serial/ID_PATH/bounded-fallback identity. */
64
+ export function physicalModemId(value) {
65
+ const [source, identityPart] = splitPhysicalModemId(value.trim());
66
+ assertSafeIdentityPart(identityPart);
67
+ if (source === 'fallback' && identityPart.length > FALLBACK_MAX_LENGTH) {
68
+ throw new PhysicalModemIdentityError('fallback-too-long');
69
+ }
70
+ return `${source}:${identityPart}`;
71
+ }
72
+ /** Construct the actor/storage key for a validated physical modem identity. */
73
+ export function stableKeyFromPhysicalModemId(id) {
74
+ return `modem:${id}`;
75
+ }
76
+ /** Parse a canonical stable key while re-validating its embedded physical identity. */
77
+ export function stableKey(value) {
78
+ if (!value.startsWith('modem:')) {
79
+ throw new PhysicalModemIdentityError('unsupported-shape');
80
+ }
81
+ return stableKeyFromPhysicalModemId(physicalModemId(value.slice('modem:'.length)));
82
+ }
83
+ /** Resolve one identity with the frozen serial → ID_PATH → bounded-fallback precedence. */
84
+ export function resolvePhysicalModemIdentity(facts) {
85
+ const candidates = [
86
+ ['serial', facts.serial],
87
+ ['id-path', facts.idPath],
88
+ ['fallback', facts.fallback],
89
+ ];
90
+ for (const [source, candidate] of candidates) {
91
+ const normalized = candidate?.trim();
92
+ if (normalized !== undefined && normalized.length > 0) {
93
+ const id = physicalModemId(`${source}:${normalized}`);
94
+ return { physicalModemId: id, stableKey: stableKeyFromPhysicalModemId(id), source };
95
+ }
96
+ }
97
+ throw new PhysicalModemIdentityError('no-identity-facts');
98
+ }
99
+ export function mintLinkId(identityKey) {
100
+ return `lnk_${createHash('sha256').update(identityKey).digest('hex').slice(0, 16)}`;
101
+ }
102
+ export function resolvePortablePhysicalIdentity(observation) {
103
+ const serial = observation.serial?.trim();
104
+ const idPath = observation.idPath?.trim();
105
+ const vendor = observation.vendorId?.trim().toLowerCase();
106
+ const identityKey = serial
107
+ ? `usb-serial:${vendor ? `${vendor}:` : ''}${serial}`
108
+ : idPath
109
+ ? `id-path:${idPath}`
110
+ : `ifname:${observation.ifname}`;
111
+ const anchor = serial ? 'usb-serial' : idPath ? 'id-path' : 'ifname';
112
+ return { identityKey, anchor, linkId: mintLinkId(identityKey) };
113
+ }
@@ -1,14 +1,5 @@
1
- // Durable desired-state policy the operator's intent for one modem.
2
- //
3
- // A2.1 stubbed this shape so the domain could enforce "an ambiguous identity may
4
- // never bind durable policy" (see `policyBindingKey`). A2.2 owns the REAL
5
- // definition below: the full connection / roaming / radio / simSlot / recovery /
6
- // usage intent the desired-state planner reconciles (see `../ports/reconcile`).
7
-
8
- import type { EquipmentId, LogicalSlotId, ModemIdentity } from './identity';
9
- import { assertCanBindPolicy } from './identity';
10
- import type { RadioAccessTechnology } from './state';
11
-
1
+ import type { EquipmentId, LogicalSlotId, ModemIdentity } from './identity.js';
2
+ import type { RadioAccessTechnology } from './state.js';
12
3
  /**
13
4
  * The subset of identity a durable policy is allowed to key off.
14
5
  *
@@ -17,13 +8,11 @@ import type { RadioAccessTechnology } from './state';
17
8
  * anchored by the equipment id — never to a per-boot handle or a subscriber id.
18
9
  */
19
10
  export interface PolicyBindingKey {
20
- readonly logicalSlotId?: LogicalSlotId;
21
- readonly equipmentId: EquipmentId;
11
+ readonly logicalSlotId?: LogicalSlotId;
12
+ readonly equipmentId: EquipmentId;
22
13
  }
23
-
24
14
  /** IP address family a connection requests. */
25
15
  export type IpFamily = 'ipv4' | 'ipv6' | 'ipv4v6';
26
-
27
16
  /**
28
17
  * Connection credentials. TODAY'S SEMANTICS (draft §round-5 auth): these are
29
18
  * persisted ONLY in the NetworkManager profile; the controller keeps them
@@ -31,24 +20,22 @@ export type IpFamily = 'ipv4' | 'ipv6' | 'ipv4v6';
31
20
  * SENSITIVE and is ALWAYS redacted in logs / output / receipts (see `../redact`).
32
21
  */
33
22
  export interface DesiredAuth {
34
- readonly username?: string;
35
- /** SENSITIVE — always redacted; NM-profile-persisted only, transient in memory. */
36
- readonly password?: string;
23
+ readonly username?: string;
24
+ /** SENSITIVE — always redacted; NM-profile-persisted only, transient in memory. */
25
+ readonly password?: string;
37
26
  }
38
-
39
27
  /** The data-connection intent. `apn: "auto"` selects NM Auto-APN (A4.1). */
40
28
  export interface DesiredConnection {
41
- readonly apn: 'auto' | string;
42
- readonly ipFamily: IpFamily;
43
- readonly auth?: DesiredAuth;
44
- /**
45
- * Manual operator selection (`gsm.network-id`) — pin registration to a specific
46
- * PLMN. Honored only while roaming (A4.1 amendment): the NM profile writes
47
- * `gsm.network-id = roaming ? networkId : ""`, so it is cleared when roaming is off.
48
- */
49
- readonly networkId?: string;
29
+ readonly apn: 'auto' | string;
30
+ readonly ipFamily: IpFamily;
31
+ readonly auth?: DesiredAuth;
32
+ /**
33
+ * Manual operator selection (`gsm.network-id`) — pin registration to a specific
34
+ * PLMN. Honored only while roaming (A4.1 amendment): the NM profile writes
35
+ * `gsm.network-id = roaming ? networkId : ""`, so it is cleared when roaming is off.
36
+ */
37
+ readonly networkId?: string;
50
38
  }
51
-
52
39
  /**
53
40
  * Radio access-technology intent. `preferenceOrdered` is ranked most-preferred
54
41
  * first ("prefer 5G" ⇒ `['5gnr', 'lte', …]`); it must be honored as a PREFERENCE,
@@ -57,27 +44,24 @@ export interface DesiredConnection {
57
44
  * when present, hard-limits the technologies the modem may use at all.
58
45
  */
59
46
  export interface DesiredRadio {
60
- readonly preferenceOrdered: readonly RadioAccessTechnology[];
61
- readonly allowedSet?: ReadonlySet<RadioAccessTechnology>;
47
+ readonly preferenceOrdered: readonly RadioAccessTechnology[];
48
+ readonly allowedSet?: ReadonlySet<RadioAccessTechnology>;
62
49
  }
63
-
64
50
  /**
65
51
  * Recovery intent. DISABLED BY DEFAULT — the evidence-gated recovery ladder (A3.4)
66
52
  * adds the per-step budgets / cooldowns; in Phase A `enabled` defaults to `false`
67
53
  * and no recovery action is ever taken unless it is explicitly turned on.
68
54
  */
69
55
  export interface DesiredRecovery {
70
- readonly enabled: boolean;
56
+ readonly enabled: boolean;
71
57
  }
72
-
73
58
  /** Data-usage policy — local-controller owned (see ports README ownership table). */
74
59
  export interface DesiredUsage {
75
- /** Day of month (1–31) the usage cycle resets; UTC, month-length clamped (A4.3). */
76
- readonly cycleDay?: number;
77
- /** Advisory threshold in bytes; crossing it raises an advisory, never gates. */
78
- readonly thresholdBytes?: number;
60
+ /** Day of month (1–31) the usage cycle resets; UTC, month-length clamped (A4.3). */
61
+ readonly cycleDay?: number;
62
+ /** Advisory threshold in bytes; crossing it raises an advisory, never gates. */
63
+ readonly thresholdBytes?: number;
79
64
  }
80
-
81
65
  /**
82
66
  * Operator-authored durable cellular policy, bound to a high/medium-confidence
83
67
  * identity via `boundTo` (a low-confidence identity cannot produce a binding key,
@@ -92,46 +76,27 @@ export interface DesiredUsage {
92
76
  * - usage — data-usage cycle + advisory threshold.
93
77
  */
94
78
  export interface DesiredCellularPolicy {
95
- readonly boundTo: PolicyBindingKey;
96
- readonly enabled: boolean;
97
- readonly connection: DesiredConnection;
98
- readonly roaming: boolean;
99
- readonly radio: DesiredRadio;
100
- readonly simSlot?: number;
101
- readonly recovery: DesiredRecovery;
102
- readonly usage: DesiredUsage;
79
+ readonly boundTo: PolicyBindingKey;
80
+ readonly enabled: boolean;
81
+ readonly connection: DesiredConnection;
82
+ readonly roaming: boolean;
83
+ readonly radio: DesiredRadio;
84
+ readonly simSlot?: number;
85
+ readonly recovery: DesiredRecovery;
86
+ readonly usage: DesiredUsage;
103
87
  }
104
-
105
88
  /** Recovery disabled — the Phase-A default (A3.4 adds budgets / cooldowns). */
106
- export const RECOVERY_DISABLED: DesiredRecovery = { enabled: false };
107
-
89
+ export declare const RECOVERY_DISABLED: DesiredRecovery;
108
90
  /**
109
91
  * Build a sensible default policy for a bindable identity: NM activation on,
110
92
  * Auto-APN, dual-stack IP, roaming off, prefer newest RAT down to GSM, recovery
111
93
  * disabled, no usage limits. Concrete adapters and the planner refine from here.
112
94
  */
113
- export function defaultCellularPolicy(boundTo: PolicyBindingKey): DesiredCellularPolicy {
114
- return {
115
- boundTo,
116
- enabled: true,
117
- connection: { apn: 'auto', ipFamily: 'ipv4v6' },
118
- roaming: false,
119
- radio: { preferenceOrdered: ['5gnr', 'lte', 'umts', 'gsm'] },
120
- recovery: RECOVERY_DISABLED,
121
- usage: {},
122
- };
123
- }
124
-
95
+ export declare function defaultCellularPolicy(boundTo: PolicyBindingKey): DesiredCellularPolicy;
125
96
  /**
126
97
  * Derive the durable binding key for an identity, REFUSING low-confidence
127
98
  * (ambiguous) identities. This is the structural gate that makes it impossible to
128
99
  * bind durable policy to a duplicate/zero-IMEI modem: no key can be produced, so
129
100
  * no `DesiredCellularPolicy` can name it. Throws `PolicyBindingRefusedError`.
130
101
  */
131
- export function policyBindingKey(identity: ModemIdentity): PolicyBindingKey {
132
- assertCanBindPolicy(identity);
133
- // exactOptionalPropertyTypes: only include logicalSlotId when actually present.
134
- return identity.logicalSlotId !== undefined
135
- ? { logicalSlotId: identity.logicalSlotId, equipmentId: identity.equipmentId }
136
- : { equipmentId: identity.equipmentId };
137
- }
102
+ export declare function policyBindingKey(identity: ModemIdentity): PolicyBindingKey;
@@ -0,0 +1,38 @@
1
+ // Durable desired-state policy — the operator's intent for one modem.
2
+ //
3
+ // A2.1 stubbed this shape so the domain could enforce "an ambiguous identity may
4
+ // never bind durable policy" (see `policyBindingKey`). A2.2 owns the REAL
5
+ // definition below: the full connection / roaming / radio / simSlot / recovery /
6
+ // usage intent the desired-state planner reconciles (see `../ports/reconcile`).
7
+ import { assertCanBindPolicy } from './identity.js';
8
+ /** Recovery disabled — the Phase-A default (A3.4 adds budgets / cooldowns). */
9
+ export const RECOVERY_DISABLED = { enabled: false };
10
+ /**
11
+ * Build a sensible default policy for a bindable identity: NM activation on,
12
+ * Auto-APN, dual-stack IP, roaming off, prefer newest RAT down to GSM, recovery
13
+ * disabled, no usage limits. Concrete adapters and the planner refine from here.
14
+ */
15
+ export function defaultCellularPolicy(boundTo) {
16
+ return {
17
+ boundTo,
18
+ enabled: true,
19
+ connection: { apn: 'auto', ipFamily: 'ipv4v6' },
20
+ roaming: false,
21
+ radio: { preferenceOrdered: ['5gnr', 'lte', 'umts', 'gsm'] },
22
+ recovery: RECOVERY_DISABLED,
23
+ usage: {},
24
+ };
25
+ }
26
+ /**
27
+ * Derive the durable binding key for an identity, REFUSING low-confidence
28
+ * (ambiguous) identities. This is the structural gate that makes it impossible to
29
+ * bind durable policy to a duplicate/zero-IMEI modem: no key can be produced, so
30
+ * no `DesiredCellularPolicy` can name it. Throws `PolicyBindingRefusedError`.
31
+ */
32
+ export function policyBindingKey(identity) {
33
+ assertCanBindPolicy(identity);
34
+ // exactOptionalPropertyTypes: only include logicalSlotId when actually present.
35
+ return identity.logicalSlotId !== undefined
36
+ ? { logicalSlotId: identity.logicalSlotId, equipmentId: identity.equipmentId }
37
+ : { equipmentId: identity.equipmentId };
38
+ }
@@ -0,0 +1,27 @@
1
+ export type ShadowGeneration = '2G' | '3G' | '4G' | '5G';
2
+ export type ShadowSignalBucket = 'none' | 'poor' | 'fair' | 'good' | 'excellent';
3
+ export interface ShadowModemState {
4
+ readonly deviceKey: string;
5
+ readonly present: boolean;
6
+ readonly registration?: string;
7
+ readonly signalBucket?: ShadowSignalBucket;
8
+ readonly operatorName?: string;
9
+ readonly simPresent?: boolean;
10
+ readonly networkType?: ShadowGeneration;
11
+ }
12
+ export declare const SHADOW_COMPARABLE_FIELDS: readonly ['present', 'registration', 'signalBucket', 'operatorName', 'simPresent', 'networkType'];
13
+ export type ShadowComparableField = (typeof SHADOW_COMPARABLE_FIELDS)[number];
14
+ export interface ShadowFieldDivergence {
15
+ readonly field: ShadowComparableField;
16
+ readonly mmcli: unknown;
17
+ readonly dbus: unknown;
18
+ }
19
+ export interface ShadowModemDivergence {
20
+ readonly deviceKey: string;
21
+ readonly kind: 'only-in-mmcli' | 'only-in-dbus' | 'field-mismatch';
22
+ readonly fields?: readonly ShadowFieldDivergence[];
23
+ }
24
+ export declare function classifyShadowDivergences(mmcli: readonly ShadowModemState[], dbus: readonly ShadowModemState[]): ShadowModemDivergence[];
25
+ export declare function foldGeneration(token: string): ShadowGeneration | undefined;
26
+ export declare function foldGenerations(tokens: Iterable<string>): ShadowGeneration | undefined;
27
+ export declare function foldSignalBucket(quality: number | undefined): ShadowSignalBucket | undefined;