@ceralive/modem-control 0.2.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +317 -0
  2. package/dist/backend/at-lease.d.ts +57 -0
  3. package/dist/backend/at-lease.js +109 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +76 -0
  61. package/dist/backend/transition-preconditions.js +64 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +196 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +19 -0
  146. package/dist/index.js +26 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +47 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operations/contracts.d.ts +72 -0
  196. package/dist/operations/contracts.js +1 -0
  197. package/dist/operations/index.d.ts +1 -0
  198. package/dist/operations/index.js +1 -0
  199. package/dist/operations/operation-engine.d.ts +16 -0
  200. package/dist/operations/operation-engine.js +194 -0
  201. package/dist/ports/index.d.ts +12 -0
  202. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  203. package/dist/ports/location.d.ts +87 -0
  204. package/dist/ports/location.js +36 -0
  205. package/dist/ports/modem-manager.d.ts +89 -0
  206. package/dist/ports/modem-manager.js +9 -0
  207. package/dist/ports/mutation-admission.d.ts +27 -0
  208. package/dist/ports/mutation-admission.js +9 -0
  209. package/dist/ports/network-manager.d.ts +68 -0
  210. package/dist/ports/network-manager.js +13 -0
  211. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  212. package/dist/ports/observation.js +7 -0
  213. package/dist/ports/ops.d.ts +44 -0
  214. package/dist/ports/ops.js +16 -0
  215. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  216. package/dist/ports/receipts.js +9 -0
  217. package/dist/ports/reconcile.d.ts +33 -0
  218. package/dist/ports/reconcile.js +200 -0
  219. package/dist/ports/resource-ownership.d.ts +29 -0
  220. package/dist/ports/resource-ownership.js +1 -0
  221. package/dist/ports/router.d.ts +19 -0
  222. package/dist/ports/router.js +7 -0
  223. package/dist/ports/sms.d.ts +64 -0
  224. package/dist/ports/sms.js +24 -0
  225. package/dist/ports/uhubctl.d.ts +6 -0
  226. package/dist/ports/uhubctl.js +1 -0
  227. package/dist/providers/contracts.d.ts +124 -0
  228. package/dist/providers/contracts.js +10 -0
  229. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  230. package/dist/providers/huawei-hilink/index.js +2 -0
  231. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  232. package/dist/providers/huawei-hilink/operations.js +56 -0
  233. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  234. package/dist/providers/huawei-hilink/provider.js +76 -0
  235. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  236. package/dist/providers/huawei-hilink/runtime.js +171 -0
  237. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  238. package/dist/providers/huawei-hilink/session.js +120 -0
  239. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  240. package/dist/providers/huawei-hilink/transport.js +1 -0
  241. package/dist/providers/index.d.ts +8 -0
  242. package/dist/providers/index.js +8 -0
  243. package/dist/providers/matcher.d.ts +3 -0
  244. package/dist/providers/matcher.js +205 -0
  245. package/dist/providers/modem-manager/errors.d.ts +7 -0
  246. package/dist/providers/modem-manager/errors.js +37 -0
  247. package/dist/providers/modem-manager/generic-operations.d.ts +8 -0
  248. package/dist/providers/modem-manager/generic-operations.js +207 -0
  249. package/dist/providers/modem-manager/index.d.ts +3 -0
  250. package/dist/providers/modem-manager/index.js +3 -0
  251. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  252. package/dist/providers/modem-manager/module-operations.js +118 -0
  253. package/dist/providers/modem-manager/provider.d.ts +39 -0
  254. package/dist/providers/modem-manager/provider.js +152 -0
  255. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  256. package/dist/providers/modem-manager/snapshot.js +204 -0
  257. package/dist/providers/modem-manager/types.d.ts +135 -0
  258. package/dist/providers/modem-manager/types.js +1 -0
  259. package/dist/providers/network-manager/adapter.d.ts +71 -0
  260. package/dist/providers/network-manager/adapter.js +348 -0
  261. package/dist/providers/network-manager/index.d.ts +2 -0
  262. package/dist/providers/network-manager/index.js +2 -0
  263. package/dist/providers/network-manager/types.d.ts +163 -0
  264. package/dist/providers/network-manager/types.js +77 -0
  265. package/dist/providers/registry.d.ts +13 -0
  266. package/dist/providers/registry.js +33 -0
  267. package/dist/providers/ufi-himi/index.d.ts +6 -0
  268. package/dist/providers/ufi-himi/index.js +6 -0
  269. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  270. package/dist/providers/ufi-himi/operations.js +66 -0
  271. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  272. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  273. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  274. package/dist/providers/ufi-himi/provider.js +204 -0
  275. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  276. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  277. package/dist/providers/ufi-himi/session.d.ts +46 -0
  278. package/dist/providers/ufi-himi/session.js +92 -0
  279. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  280. package/dist/providers/ufi-himi/transport.js +25 -0
  281. package/dist/providers/zte-goform/index.d.ts +2 -0
  282. package/dist/providers/zte-goform/index.js +2 -0
  283. package/dist/providers/zte-goform/provider.d.ts +51 -0
  284. package/dist/providers/zte-goform/provider.js +101 -0
  285. package/dist/providers/zte-goform/session.d.ts +17 -0
  286. package/dist/providers/zte-goform/session.js +133 -0
  287. package/dist/providers/zte-goform/transport.d.ts +16 -0
  288. package/dist/providers/zte-goform/transport.js +1 -0
  289. package/dist/radio/band-truth.d.ts +50 -0
  290. package/dist/radio/band-truth.js +92 -0
  291. package/dist/radio/index.d.ts +3 -0
  292. package/dist/radio/index.js +10 -0
  293. package/dist/radio/mode-combinations.d.ts +78 -0
  294. package/dist/radio/mode-combinations.js +198 -0
  295. package/dist/radio/mode-truth.d.ts +67 -0
  296. package/dist/radio/mode-truth.js +112 -0
  297. package/dist/redact.d.ts +15 -0
  298. package/dist/redact.js +189 -0
  299. package/dist/safety/composition-root.d.ts +28 -0
  300. package/dist/safety/composition-root.js +65 -0
  301. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  302. package/dist/safety/flock-resource-ownership.js +151 -0
  303. package/dist/safety/index.d.ts +2 -0
  304. package/dist/safety/index.js +2 -0
  305. package/dist/sms/dbus-messaging.d.ts +17 -0
  306. package/dist/sms/dbus-messaging.js +185 -0
  307. package/dist/sms/inbox-store.d.ts +10 -0
  308. package/dist/sms/inbox-store.js +82 -0
  309. package/dist/sms/index.d.ts +4 -0
  310. package/dist/sms/index.js +10 -0
  311. package/dist/sms/mmcli-parse.d.ts +54 -0
  312. package/dist/sms/mmcli-parse.js +224 -0
  313. package/dist/sms/normalize.d.ts +42 -0
  314. package/dist/sms/normalize.js +95 -0
  315. package/dist/testing/domain-fakes.d.ts +58 -0
  316. package/dist/testing/domain-fakes.js +98 -0
  317. package/dist/testing/index.d.ts +2 -0
  318. package/dist/testing/index.js +17 -0
  319. package/dist/testing/provider-fakes.d.ts +45 -0
  320. package/dist/testing/provider-fakes.js +64 -0
  321. package/dist/transport/calls.d.ts +9 -0
  322. package/dist/transport/calls.js +88 -0
  323. package/dist/transport/codec.d.ts +3 -0
  324. package/dist/transport/codec.js +207 -0
  325. package/dist/transport/dbus-native.d.ts +57 -0
  326. package/dist/transport/dbus-native.js +17 -0
  327. package/dist/transport/errors.d.ts +21 -0
  328. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  329. package/dist/transport/index.d.ts +4 -0
  330. package/dist/transport/index.js +9 -0
  331. package/dist/transport/signals.d.ts +15 -0
  332. package/dist/transport/signals.js +123 -0
  333. package/dist/transport/signature.d.ts +7 -0
  334. package/dist/transport/signature.js +94 -0
  335. package/dist/transport/transport.d.ts +2 -0
  336. package/dist/transport/transport.js +202 -0
  337. package/dist/transport/types.d.ts +61 -0
  338. package/dist/transport/types.js +19 -0
  339. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  340. package/dist/usb-mode/catalog-schema.js +97 -0
  341. package/dist/usb-mode/catalog.d.ts +21 -0
  342. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  343. package/dist/usb-mode/certified-catalog.json +67 -0
  344. package/dist/usb-mode/index.d.ts +5 -0
  345. package/dist/usb-mode/index.js +15 -0
  346. package/dist/usb-mode/ingestion.d.ts +111 -0
  347. package/dist/usb-mode/ingestion.js +187 -0
  348. package/dist/usb-mode/promotion-review.d.ts +21 -0
  349. package/dist/usb-mode/promotion-review.js +87 -0
  350. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  351. package/dist/usb-mode/usb-devices-parse.js +157 -0
  352. package/dist/ussd/calls.d.ts +32 -0
  353. package/dist/ussd/calls.js +96 -0
  354. package/dist/ussd/index.d.ts +5 -0
  355. package/dist/ussd/index.js +12 -0
  356. package/dist/ussd/mm-ussd.d.ts +37 -0
  357. package/dist/ussd/mm-ussd.js +205 -0
  358. package/dist/ussd/refusal.d.ts +53 -0
  359. package/dist/ussd/refusal.js +154 -0
  360. package/dist/ussd/registration.d.ts +20 -0
  361. package/dist/ussd/registration.js +101 -0
  362. package/dist/ussd/session.d.ts +84 -0
  363. package/dist/ussd/session.js +163 -0
  364. package/package.json +38 -4
  365. package/src/backend/at-lease.test.ts +0 -106
  366. package/src/backend/at-lease.ts +0 -158
  367. package/src/backend/cell-info.test.ts +0 -154
  368. package/src/backend/cell-info.ts +0 -160
  369. package/src/backend/device-classifier.test.ts +0 -168
  370. package/src/backend/device-classifier.ts +0 -248
  371. package/src/backend/enrichment.ts +0 -96
  372. package/src/backend/features.test.ts +0 -162
  373. package/src/backend/features.ts +0 -179
  374. package/src/backend/identity-ladder.test.ts +0 -117
  375. package/src/backend/identity-ladder.ts +0 -221
  376. package/src/backend/identity-registry.test.ts +0 -89
  377. package/src/backend/identity-registry.ts +0 -151
  378. package/src/backend/index.ts +0 -221
  379. package/src/backend/lifecycle-interlock.ts +0 -38
  380. package/src/backend/managed-objects.ts +0 -108
  381. package/src/backend/mapping.ts +0 -160
  382. package/src/backend/mm-backend.ts +0 -191
  383. package/src/backend/mm-mutations.ts +0 -228
  384. package/src/backend/modem-actor.test.ts +0 -95
  385. package/src/backend/modem-actor.ts +0 -112
  386. package/src/backend/nm-auto-apn.ts +0 -161
  387. package/src/backend/nm-gsm-fields.ts +0 -122
  388. package/src/backend/nmcli-nm-port.ts +0 -228
  389. package/src/backend/nmcli-runner.ts +0 -52
  390. package/src/backend/observer.ts +0 -297
  391. package/src/backend/power-contract.test.ts +0 -40
  392. package/src/backend/power-contract.ts +0 -83
  393. package/src/backend/recovery-attribution.test.ts +0 -102
  394. package/src/backend/recovery-attribution.ts +0 -86
  395. package/src/backend/recovery-budget.test.ts +0 -64
  396. package/src/backend/recovery-budget.ts +0 -84
  397. package/src/backend/recovery-ladder.test.ts +0 -257
  398. package/src/backend/recovery-ladder.ts +0 -249
  399. package/src/backend/router-ethernet.test.ts +0 -71
  400. package/src/backend/router-ethernet.ts +0 -90
  401. package/src/backend/row-store.ts +0 -105
  402. package/src/backend/signal-setup.ts +0 -112
  403. package/src/backend/sim-unlock.ts +0 -193
  404. package/src/backend/transition-preconditions.ts +0 -149
  405. package/src/backend/usage/accounting.test.ts +0 -147
  406. package/src/backend/usage/accounting.ts +0 -123
  407. package/src/backend/usage/billing-cycle.test.ts +0 -62
  408. package/src/backend/usage/billing-cycle.ts +0 -45
  409. package/src/backend/usage/index.ts +0 -37
  410. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  411. package/src/backend/usage/sampler.test.ts +0 -219
  412. package/src/backend/usage/sampler.ts +0 -228
  413. package/src/backend/usage/store.test.ts +0 -148
  414. package/src/backend/usage/store.ts +0 -177
  415. package/src/backend/usb-enumerator.test.ts +0 -87
  416. package/src/backend/usb-enumerator.ts +0 -181
  417. package/src/backend/usb-mode-transition.test.ts +0 -323
  418. package/src/backend/usb-mode-transition.ts +0 -253
  419. package/src/domain/brand.ts +0 -29
  420. package/src/domain/errors.ts +0 -77
  421. package/src/domain/guards.test.ts +0 -218
  422. package/src/domain/guards.ts +0 -144
  423. package/src/domain/identity.test.ts +0 -83
  424. package/src/domain/identity.ts +0 -165
  425. package/src/domain/index.ts +0 -12
  426. package/src/domain/snapshot.test.ts +0 -266
  427. package/src/domain/snapshot.ts +0 -120
  428. package/src/index.test.ts +0 -6
  429. package/src/index.ts +0 -15
  430. package/src/ports/README.md +0 -61
  431. package/src/ports/forbidden-surface.test.ts +0 -241
  432. package/src/ports/modem-manager.ts +0 -72
  433. package/src/ports/network-manager.ts +0 -87
  434. package/src/ports/ops.ts +0 -60
  435. package/src/ports/ops.type-test.ts +0 -39
  436. package/src/ports/receipts.test.ts +0 -153
  437. package/src/ports/reconcile.test.ts +0 -152
  438. package/src/ports/reconcile.ts +0 -338
  439. package/src/ports/router.ts +0 -29
  440. package/src/redact.test.ts +0 -82
  441. package/src/redact.ts +0 -73
  442. package/src/transport/README.md +0 -65
  443. package/src/transport/calls.ts +0 -113
  444. package/src/transport/characterization.test.ts +0 -260
  445. package/src/transport/codec.test.ts +0 -118
  446. package/src/transport/codec.ts +0 -240
  447. package/src/transport/conformance-python.test.ts +0 -152
  448. package/src/transport/conformance-same-lib.test.ts +0 -115
  449. package/src/transport/dbus-native-lib.d.ts +0 -19
  450. package/src/transport/dbus-native.ts +0 -85
  451. package/src/transport/index.ts +0 -30
  452. package/src/transport/no-library-leak.test.ts +0 -61
  453. package/src/transport/reliability.test.ts +0 -173
  454. package/src/transport/signals.ts +0 -150
  455. package/src/transport/signature.ts +0 -110
  456. package/src/transport/test-support/fake-service.ts +0 -168
  457. package/src/transport/test-support/independent-producer.py +0 -110
  458. package/src/transport/test-support/private-bus.ts +0 -66
  459. package/src/transport/transport.ts +0 -250
  460. package/src/transport/types.ts +0 -118
  461. package/src/usb-mode/catalog-schema.test.ts +0 -181
  462. package/src/usb-mode/catalog-schema.ts +0 -113
  463. package/src/usb-mode/certified-catalog.json +0 -67
  464. package/src/usb-mode/index.ts +0 -27
@@ -0,0 +1,19 @@
1
+ export declare const PACKAGE_NAME = "@ceralive/modem-control";
2
+ export * from './backend/index.js';
3
+ export * from './band/index.js';
4
+ export * from './capability/index.js';
5
+ export * from './domain/index.js';
6
+ export * from './fcc/index.js';
7
+ export * from './hardware/router-parsers.js';
8
+ export * from './journal/index.js';
9
+ export * from './location/index.js';
10
+ export * from './observations/index.js';
11
+ export * from './operations/index.js';
12
+ export * from './ports/index.js';
13
+ export * from './providers/index.js';
14
+ export * from './radio/index.js';
15
+ export * from './redact.js';
16
+ export * from './safety/index.js';
17
+ export * from './sms/index.js';
18
+ export * from './usb-mode/index.js';
19
+ export * from './ussd/index.js';
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ // @ceralive/modem-control — package entry point.
2
+ //
3
+ // Phase A: the domain model (identity + orthogonal state + revisions) under
4
+ // `./domain`, the MM / NM / Router port contracts + desired-state planner under
5
+ // `./ports`, the redaction module (`./redact`), and the epoch-scoped ModemManager
6
+ // D-Bus observer under `./backend`. The NetworkManager adapter, USB composition-mode
7
+ // model, and data-usage sampler land in later waves.
8
+ export const PACKAGE_NAME = '@ceralive/modem-control';
9
+ export * from './backend/index.js';
10
+ export * from './band/index.js';
11
+ export * from './capability/index.js';
12
+ export * from './domain/index.js';
13
+ export * from './fcc/index.js';
14
+ export * from './hardware/router-parsers.js';
15
+ export * from './journal/index.js';
16
+ export * from './location/index.js';
17
+ export * from './observations/index.js';
18
+ export * from './operations/index.js';
19
+ export * from './ports/index.js';
20
+ export * from './providers/index.js';
21
+ export * from './radio/index.js';
22
+ export * from './redact.js';
23
+ export * from './safety/index.js';
24
+ export * from './sms/index.js';
25
+ export * from './usb-mode/index.js';
26
+ export * from './ussd/index.js';
@@ -0,0 +1,44 @@
1
+ import { type JournalEntry } from './entry.js';
2
+ /** Why one record could not be read. `field` names the offending key, never its value. */
3
+ export interface JournalDecodeFailure {
4
+ readonly code: 'empty' | 'invalid-json' | 'not-an-object' | 'unsupported-schema-version' | 'schema-mismatch' | 'unreadable';
5
+ readonly field?: string;
6
+ /** Byte offset for a JSON syntax error, when the runtime reported one. */
7
+ readonly offset?: number;
8
+ }
9
+ export type JournalDecodeResult<T> = {
10
+ readonly ok: true;
11
+ readonly value: T;
12
+ } | {
13
+ readonly ok: false;
14
+ readonly failure: JournalDecodeFailure;
15
+ };
16
+ declare function record(raw: unknown, field: string): Record<string, unknown>;
17
+ declare function requiredString(source: Record<string, unknown>, field: string): string;
18
+ declare function optionalString(source: Record<string, unknown>, field: string): string | undefined;
19
+ declare function requiredNonNegativeInteger(source: Record<string, unknown>, field: string): number;
20
+ declare function member<T extends string>(source: Record<string, unknown>, field: string, allowed: readonly T[]): T;
21
+ /**
22
+ * Serialize one entry to a single line WITHOUT its terminator.
23
+ *
24
+ * Keys are emitted in a fixed order because the round-trip tests compare bytes,
25
+ * and byte comparison is the only assertion that catches a field a reader silently
26
+ * dropped (`JSON.parse` + a permissive validator will happily lose one and still
27
+ * report success — the same trap the srtla telemetry byte-parity suite exists for).
28
+ */
29
+ export declare function encodeJournalEntry(entry: JournalEntry): string;
30
+ /** Decode one line. An empty/whitespace-only line is reported, never silently dropped. */
31
+ export declare function decodeJournalEntry(line: string): JournalDecodeResult<JournalEntry>;
32
+ /** Decode an arbitrary JSON document with a caller-supplied validator. */
33
+ export declare function decodeJournalDocument<T>(text: string, validate: (raw: unknown) => T): JournalDecodeResult<T>;
34
+ /** The validator helpers the legacy reader reuses, so both shapes fail the same way. */
35
+ export declare const journalSchema: {
36
+ readonly record: typeof record;
37
+ readonly requiredString: typeof requiredString;
38
+ readonly optionalString: typeof optionalString;
39
+ readonly requiredNonNegativeInteger: typeof requiredNonNegativeInteger;
40
+ readonly member: typeof member;
41
+ readonly schemaError: (field: string) => Error;
42
+ readonly schemaVersionError: () => Error;
43
+ };
44
+ export {};
@@ -0,0 +1,198 @@
1
+ // Line codec for the journal: exactly one entry per line, JSON, no wrapper.
2
+ //
3
+ // WHY DECODING RETURNS A RESULT INSTEAD OF THROWING. A journal is read at exactly
4
+ // one moment — recovery after an unclean restart — and that is the moment a throw
5
+ // is most expensive: it aborts the read at the first damaged byte and takes every
6
+ // still-valid entry after it with it. The whole point of this module is that a
7
+ // damaged record is DATA, reported alongside the records that survived, so nothing
8
+ // earlier or later is discarded to make one bad line disappear.
9
+ //
10
+ // FAILURES NAME A FIELD, NEVER CONTENT. Same rule the two policy stores follow: a
11
+ // classification carries the offending field name and a byte count, never the bytes
12
+ // themselves, because a journal line can hold provider identifiers and refusal
13
+ // reasons and a log line is the wrong place to reproduce them.
14
+ import { MODEM_CONTROL_JOURNAL_SCHEMA_VERSION, } from './entry.js';
15
+ class SchemaError extends Error {
16
+ field;
17
+ constructor(field) {
18
+ super(`schema-mismatch: ${field}`);
19
+ this.field = field;
20
+ }
21
+ }
22
+ class SchemaVersionError extends Error {
23
+ constructor() {
24
+ super('unsupported-schema-version');
25
+ }
26
+ }
27
+ function record(raw, field) {
28
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
29
+ throw new SchemaError(field);
30
+ return raw;
31
+ }
32
+ function requiredString(source, field) {
33
+ const value = source[field];
34
+ if (typeof value !== 'string' || value.length === 0)
35
+ throw new SchemaError(field);
36
+ return value;
37
+ }
38
+ function optionalString(source, field) {
39
+ const value = source[field];
40
+ if (value === undefined)
41
+ return undefined;
42
+ if (typeof value !== 'string')
43
+ throw new SchemaError(field);
44
+ return value;
45
+ }
46
+ function requiredNonNegativeInteger(source, field) {
47
+ const value = source[field];
48
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
49
+ throw new SchemaError(field);
50
+ }
51
+ return value;
52
+ }
53
+ function requiredStringArray(source, field) {
54
+ const value = source[field];
55
+ if (!Array.isArray(value) || value.some((member) => typeof member !== 'string')) {
56
+ throw new SchemaError(field);
57
+ }
58
+ return value;
59
+ }
60
+ function member(source, field, allowed) {
61
+ const value = source[field];
62
+ if (typeof value !== 'string' || !allowed.includes(value)) {
63
+ throw new SchemaError(field);
64
+ }
65
+ return value;
66
+ }
67
+ const AUTHORITIES = ['provider', 'controller', 'hardware'];
68
+ const IMPACTS = ['read', 'write', 'session', 'disruptive', 'recovery'];
69
+ const CONFIDENCES = ['high', 'medium', 'low', 'unknown'];
70
+ const UNKNOWN_OUTCOME_REASONS = [
71
+ 'stale-generation',
72
+ 'write-reply-timed-out',
73
+ 'write-reply-dropped',
74
+ ];
75
+ function parseDescriptor(raw) {
76
+ const source = record(raw, 'descriptor');
77
+ return {
78
+ descriptorId: requiredString(source, 'descriptorId'),
79
+ provider: requiredString(source, 'provider'),
80
+ authority: member(source, 'authority', AUTHORITIES),
81
+ mutationImpact: member(source, 'mutationImpact', IMPACTS),
82
+ profiles: requiredStringArray(source, 'profiles'),
83
+ firmware: requiredStringArray(source, 'firmware'),
84
+ confidence: member(source, 'confidence', CONFIDENCES),
85
+ };
86
+ }
87
+ function parseOutcome(raw) {
88
+ const source = record(raw, 'outcome');
89
+ switch (member(source, 'status', ['applied', 'refused', 'failed', 'unknown-outcome'])) {
90
+ case 'applied':
91
+ return { status: 'applied' };
92
+ case 'refused':
93
+ return { status: 'refused', reason: requiredString(source, 'reason') };
94
+ case 'failed':
95
+ return { status: 'failed', reason: requiredString(source, 'reason') };
96
+ case 'unknown-outcome':
97
+ return {
98
+ status: 'unknown-outcome',
99
+ reason: member(source, 'reason', UNKNOWN_OUTCOME_REASONS),
100
+ };
101
+ }
102
+ }
103
+ function parseEntry(raw) {
104
+ const source = record(raw, 'entry');
105
+ if (source.schemaVersion !== MODEM_CONTROL_JOURNAL_SCHEMA_VERSION)
106
+ throw new SchemaVersionError();
107
+ const base = {
108
+ schemaVersion: MODEM_CONTROL_JOURNAL_SCHEMA_VERSION,
109
+ operationId: requiredString(source, 'operationId'),
110
+ physicalModemId: requiredString(source, 'physicalModemId'),
111
+ generation: requiredNonNegativeInteger(source, 'generation'),
112
+ recordedAtMs: requiredNonNegativeInteger(source, 'recordedAtMs'),
113
+ descriptor: parseDescriptor(source.descriptor),
114
+ };
115
+ if (member(source, 'phase', ['started', 'completed']) === 'started') {
116
+ return { ...base, phase: 'started' };
117
+ }
118
+ return { ...base, phase: 'completed', outcome: parseOutcome(source.outcome) };
119
+ }
120
+ /** Classify a decode failure into a metadata-only result (never raw content). */
121
+ function classify(error) {
122
+ if (error instanceof SchemaVersionError)
123
+ return { code: 'unsupported-schema-version' };
124
+ if (error instanceof SchemaError)
125
+ return { code: 'schema-mismatch', field: error.field };
126
+ if (error instanceof SyntaxError) {
127
+ const offset = /position (\d+)/.exec(error.message)?.[1];
128
+ return offset === undefined
129
+ ? { code: 'invalid-json' }
130
+ : { code: 'invalid-json', offset: Number(offset) };
131
+ }
132
+ return { code: 'unreadable' };
133
+ }
134
+ /**
135
+ * Serialize one entry to a single line WITHOUT its terminator.
136
+ *
137
+ * Keys are emitted in a fixed order because the round-trip tests compare bytes,
138
+ * and byte comparison is the only assertion that catches a field a reader silently
139
+ * dropped (`JSON.parse` + a permissive validator will happily lose one and still
140
+ * report success — the same trap the srtla telemetry byte-parity suite exists for).
141
+ */
142
+ export function encodeJournalEntry(entry) {
143
+ const descriptor = {
144
+ descriptorId: entry.descriptor.descriptorId,
145
+ provider: entry.descriptor.provider,
146
+ authority: entry.descriptor.authority,
147
+ mutationImpact: entry.descriptor.mutationImpact,
148
+ profiles: entry.descriptor.profiles,
149
+ firmware: entry.descriptor.firmware,
150
+ confidence: entry.descriptor.confidence,
151
+ };
152
+ const base = {
153
+ schemaVersion: entry.schemaVersion,
154
+ phase: entry.phase,
155
+ operationId: entry.operationId,
156
+ physicalModemId: entry.physicalModemId,
157
+ generation: entry.generation,
158
+ recordedAtMs: entry.recordedAtMs,
159
+ descriptor,
160
+ };
161
+ return JSON.stringify(entry.phase === 'started' ? base : { ...base, outcome: entry.outcome });
162
+ }
163
+ /** Decode one line. An empty/whitespace-only line is reported, never silently dropped. */
164
+ export function decodeJournalEntry(line) {
165
+ if (line.trim().length === 0)
166
+ return { ok: false, failure: { code: 'empty' } };
167
+ try {
168
+ return { ok: true, value: parseEntry(JSON.parse(line)) };
169
+ }
170
+ catch (error) {
171
+ return { ok: false, failure: classify(error) };
172
+ }
173
+ }
174
+ /** Decode an arbitrary JSON document with a caller-supplied validator. */
175
+ export function decodeJournalDocument(text, validate) {
176
+ if (text.trim().length === 0)
177
+ return { ok: false, failure: { code: 'empty' } };
178
+ try {
179
+ return { ok: true, value: validate(JSON.parse(text)) };
180
+ }
181
+ catch (error) {
182
+ return { ok: false, failure: classify(error) };
183
+ }
184
+ }
185
+ /** The validator helpers the legacy reader reuses, so both shapes fail the same way. */
186
+ export const journalSchema = {
187
+ record,
188
+ requiredString,
189
+ optionalString,
190
+ requiredNonNegativeInteger,
191
+ member,
192
+ schemaError(field) {
193
+ return new SchemaError(field);
194
+ },
195
+ schemaVersionError() {
196
+ return new SchemaVersionError();
197
+ },
198
+ };
@@ -0,0 +1,28 @@
1
+ import type { OperationJournalEvent, OperationJournalHook } from '../operations/contracts.js';
2
+ import { type JournalRecovery } from './recovery.js';
3
+ import type { JournalStore } from './store.js';
4
+ export interface JournalEngineOptions {
5
+ /** The store — and therefore the path — is supplied by the composition root. */
6
+ readonly store: JournalStore;
7
+ readonly now?: () => number;
8
+ }
9
+ export declare class JournalEngine {
10
+ #private;
11
+ constructor(options: JournalEngineOptions);
12
+ /** Where this engine journals to; useful in a recovery log line. */
13
+ get path(): string;
14
+ /**
15
+ * The `OperationJournalHook` implementation.
16
+ *
17
+ * Generic per CALL rather than per instance, so one engine journals every
18
+ * descriptor in the process. A generic method satisfies the non-generic
19
+ * `OperationJournalHook<I, O>` member by instantiation, which is what lets an
20
+ * `OperationExecution` take the engine itself as its `journal`.
21
+ */
22
+ record<I, O>(event: OperationJournalEvent<I, O>): Promise<void>;
23
+ /** An explicitly typed hook, for a caller that prefers a narrow object. */
24
+ hook<I, O>(): OperationJournalHook<I, O>;
25
+ /** Read the journal back and reconstruct what was in flight. */
26
+ recover(): Promise<JournalRecovery>;
27
+ }
28
+ export declare function createJournalEngine(options: JournalEngineOptions): JournalEngine;
@@ -0,0 +1,68 @@
1
+ // The journal engine: the operation engine's journal hook, plus replay.
2
+ //
3
+ // `OperationExecution.journal` (todo 20's `OperationJournalHook`) is the seam the
4
+ // operation engine already calls at `started` and at `completed`, and a descriptor
5
+ // that declares `journal: { required: true }` is REFUSED outright when no hook is
6
+ // supplied. This class is the durable implementation of that seam: it flattens the
7
+ // event onto a journal entry and appends it, and it reads the same file back.
8
+ //
9
+ // THE ENGINE HOLDS NO PATH. It holds a `JournalStore`, and the store was handed a
10
+ // path by whoever composed it. That is the same injection shape todo 19 used for
11
+ // the ownership lock (`FlockResourceOwnershipOptions.lockPath` is REQUIRED and the
12
+ // adapter substitutes nothing) and the same reason: an embedding process owns its
13
+ // filesystem layout, and a library that guesses one is a library that writes to the
14
+ // wrong disk on a device it has never seen.
15
+ //
16
+ // THE CLOCK IS INJECTED TOO. `now` defaults to `Date.now`, but a test that wants
17
+ // deterministic timestamps supplies its own — the observation layer's rule that
18
+ // this package never stamps data with a time it did not come from applies here as
19
+ // well, and a replay assertion over timestamps must not be a race.
20
+ import { journalDescriptorEvidence, journalOutcome } from './entry.js';
21
+ import { reconstructJournalRecovery } from './recovery.js';
22
+ export class JournalEngine {
23
+ #store;
24
+ #now;
25
+ constructor(options) {
26
+ this.#store = options.store;
27
+ this.#now = options.now ?? (() => Date.now());
28
+ }
29
+ /** Where this engine journals to; useful in a recovery log line. */
30
+ get path() {
31
+ return this.#store.path;
32
+ }
33
+ /**
34
+ * The `OperationJournalHook` implementation.
35
+ *
36
+ * Generic per CALL rather than per instance, so one engine journals every
37
+ * descriptor in the process. A generic method satisfies the non-generic
38
+ * `OperationJournalHook<I, O>` member by instantiation, which is what lets an
39
+ * `OperationExecution` take the engine itself as its `journal`.
40
+ */
41
+ record(event) {
42
+ return this.#store.append(entryFor(event, this.#now()));
43
+ }
44
+ /** An explicitly typed hook, for a caller that prefers a narrow object. */
45
+ hook() {
46
+ return { record: (event) => this.record(event) };
47
+ }
48
+ /** Read the journal back and reconstruct what was in flight. */
49
+ async recover() {
50
+ return reconstructJournalRecovery(await this.#store.read());
51
+ }
52
+ }
53
+ function entryFor(event, recordedAtMs) {
54
+ const base = {
55
+ schemaVersion: 1,
56
+ operationId: event.operationId,
57
+ physicalModemId: event.physicalModemId,
58
+ generation: event.generation,
59
+ recordedAtMs,
60
+ descriptor: journalDescriptorEvidence(event.descriptor),
61
+ };
62
+ return event.phase === 'started'
63
+ ? { ...base, phase: 'started' }
64
+ : { ...base, phase: 'completed', outcome: journalOutcome(event.result) };
65
+ }
66
+ export function createJournalEngine(options) {
67
+ return new JournalEngine(options);
68
+ }
@@ -0,0 +1,74 @@
1
+ import type { MutationImpact, OperationConfidence, OperationDescriptor, OperationResult } from '../domain/index.js';
2
+ /** The current on-disk schema version for one journal line. */
3
+ export declare const MODEM_CONTROL_JOURNAL_SCHEMA_VERSION = 1;
4
+ /** The two phases the operation engine emits, mirrored one-to-one on disk. */
5
+ export type JournalPhase = 'started' | 'completed';
6
+ /**
7
+ * How an operation ended, projected from `OperationResult` WITHOUT its value.
8
+ *
9
+ * `unknown-outcome` keeps the frozen domain reason union verbatim rather than
10
+ * widening to `string`, because those three reasons are the entire vocabulary a
11
+ * recovery pass branches on and a fourth spelling would silently read as an
12
+ * ordinary failure.
13
+ */
14
+ export type JournalOutcome = {
15
+ readonly status: 'applied';
16
+ } | {
17
+ readonly status: 'refused';
18
+ readonly reason: string;
19
+ } | {
20
+ readonly status: 'failed';
21
+ readonly reason: string;
22
+ } | {
23
+ readonly status: 'unknown-outcome';
24
+ readonly reason: 'stale-generation' | 'write-reply-timed-out' | 'write-reply-dropped';
25
+ };
26
+ /**
27
+ * The descriptor facts a recovery pass needs, flattened out of the descriptor.
28
+ *
29
+ * The descriptor itself is not persisted: it carries FUNCTIONS (`readback.matches`,
30
+ * the constraint predicates) that no serialization round-trips, so storing it would
31
+ * produce a document that reads back as a different object than it was written from.
32
+ * These are the fields that answer "what was being changed, by whom, on what
33
+ * evidence" — everything a human or a reconciler needs to judge a stranded write.
34
+ */
35
+ export interface JournalDescriptorEvidence {
36
+ readonly descriptorId: string;
37
+ readonly provider: string;
38
+ readonly authority: 'provider' | 'controller' | 'hardware';
39
+ readonly mutationImpact: MutationImpact;
40
+ readonly profiles: readonly string[];
41
+ readonly firmware: readonly string[];
42
+ readonly confidence: OperationConfidence;
43
+ }
44
+ interface JournalEntryBase {
45
+ readonly schemaVersion: typeof MODEM_CONTROL_JOURNAL_SCHEMA_VERSION;
46
+ readonly operationId: string;
47
+ /** The serialized `PhysicalModemId`. Stored as text; branding is a compile-time fact. */
48
+ readonly physicalModemId: string;
49
+ /** The serialized `DeviceGeneration` the operation was fenced to. */
50
+ readonly generation: number;
51
+ readonly recordedAtMs: number;
52
+ readonly descriptor: JournalDescriptorEvidence;
53
+ }
54
+ /**
55
+ * One journal line.
56
+ *
57
+ * The two members differ in SHAPE, not just in a label: a `started` entry has no
58
+ * `outcome` KEY at all. That is the same rule `observations/reading.ts` follows —
59
+ * a consumer cannot read an outcome off a phase that has none, so "in flight" can
60
+ * never be mistaken for "ended with an unset outcome".
61
+ */
62
+ export type JournalEntry = (JournalEntryBase & {
63
+ readonly phase: 'started';
64
+ }) | (JournalEntryBase & {
65
+ readonly phase: 'completed';
66
+ readonly outcome: JournalOutcome;
67
+ });
68
+ /** Flatten a descriptor down to the serializable evidence the journal keeps. */
69
+ export declare function journalDescriptorEvidence<I, O>(descriptor: OperationDescriptor<I, O>): JournalDescriptorEvidence;
70
+ /** Project a result onto its journalable outcome, dropping the value by design. */
71
+ export declare function journalOutcome<O>(result: OperationResult<O>): JournalOutcome;
72
+ /** True when an outcome leaves the device in a state nobody has read back. */
73
+ export declare function outcomeRequiresReconciliation(outcome: JournalOutcome): boolean;
74
+ export {};
@@ -0,0 +1,56 @@
1
+ // The transaction journal's ENTRY vocabulary.
2
+ //
3
+ // The journal exists to answer ONE question after an unclean restart: which
4
+ // mutations were in flight, and which of them ended in an outcome nobody can
5
+ // read off the device. `operations/operation-engine.ts` already closes a
6
+ // per-modem gate when a write classifies `unknown-outcome`, but that gate lives
7
+ // in a `Set` on the engine instance — a process death takes it with it. Writing
8
+ // the same two facts down is what makes the gate survive the process.
9
+ //
10
+ // WHY AN EVENT LOG AND NOT A LATEST-STATE SNAPSHOT. A started event and its
11
+ // completion are two facts separated by exactly the window a crash lands in, so
12
+ // the shape has to be able to hold the first without the second. A document that
13
+ // only ever carries "the current state" cannot distinguish "we never dispatched"
14
+ // from "we dispatched and the reply never came" unless it spends a state name on
15
+ // each — which is how CeraUI's own mutation journal does it (see
16
+ // `legacy-ceraui.ts`, which reads that shape). Both are legitimate; this one is
17
+ // append-only because appending is the only write that cannot lose a prior fact.
18
+ //
19
+ // WHAT IS DELIBERATELY NOT RECORDED: the operation's INPUT and the operation's
20
+ // RETURNED VALUE. An input is routinely a PIN, a PUK, or a USSD command carrying
21
+ // a voucher code, and a returned value is routinely a message body or a location
22
+ // fix — all of them classes `../redact.ts` masks everywhere else. The journal
23
+ // records THAT an operation ran and HOW it ended, never WHAT was sent or read.
24
+ // A caller that needs a rollback payload owns persisting it beside the journal
25
+ // under its own redaction decision.
26
+ /** The current on-disk schema version for one journal line. */
27
+ export const MODEM_CONTROL_JOURNAL_SCHEMA_VERSION = 1;
28
+ /** Flatten a descriptor down to the serializable evidence the journal keeps. */
29
+ export function journalDescriptorEvidence(descriptor) {
30
+ return {
31
+ descriptorId: descriptor.id,
32
+ provider: descriptor.provider,
33
+ authority: descriptor.authority,
34
+ mutationImpact: descriptor.mutationImpact,
35
+ profiles: [...descriptor.evidence.profiles],
36
+ firmware: [...descriptor.evidence.firmware],
37
+ confidence: descriptor.confidence,
38
+ };
39
+ }
40
+ /** Project a result onto its journalable outcome, dropping the value by design. */
41
+ export function journalOutcome(result) {
42
+ switch (result.status) {
43
+ case 'applied':
44
+ return { status: 'applied' };
45
+ case 'refused':
46
+ return { status: 'refused', reason: result.reason };
47
+ case 'failed':
48
+ return { status: 'failed', reason: result.reason };
49
+ case 'unknown-outcome':
50
+ return { status: 'unknown-outcome', reason: result.reason };
51
+ }
52
+ }
53
+ /** True when an outcome leaves the device in a state nobody has read back. */
54
+ export function outcomeRequiresReconciliation(outcome) {
55
+ return outcome.status === 'unknown-outcome';
56
+ }
@@ -0,0 +1,6 @@
1
+ export * from './codec.js';
2
+ export * from './engine.js';
3
+ export * from './entry.js';
4
+ export * from './legacy-ceraui.js';
5
+ export * from './recovery.js';
6
+ export * from './store.js';
@@ -0,0 +1,6 @@
1
+ export * from './codec.js';
2
+ export * from './engine.js';
3
+ export * from './entry.js';
4
+ export * from './legacy-ceraui.js';
5
+ export * from './recovery.js';
6
+ export * from './store.js';
@@ -0,0 +1,73 @@
1
+ import { type JournalDecodeResult } from './codec.js';
2
+ import type { JournalDescriptorEvidence } from './entry.js';
3
+ import { type JournalOperationRecord, type JournalRecovery } from './recovery.js';
4
+ /** The `version` literal CeraUI's schema pins. */
5
+ export declare const LEGACY_CERAUI_JOURNAL_VERSION = 1;
6
+ /** CeraUI's cap on retained history entries per slot. */
7
+ export declare const LEGACY_CERAUI_HISTORY_CAP = 32;
8
+ export declare const LEGACY_CERAUI_MUTATION_STATES: readonly ["armed", "executing", "completed", "failed", "acknowledged", "device-absent-quarantine", "decommissioned", "recommission-pending"];
9
+ export type LegacyCeraUiMutationState = (typeof LEGACY_CERAUI_MUTATION_STATES)[number];
10
+ export declare const LEGACY_CERAUI_ACK_MODES: readonly ["verified-rollback", "force-rebaseline"];
11
+ export type LegacyCeraUiAckMode = (typeof LEGACY_CERAUI_ACK_MODES)[number];
12
+ export interface LegacyCeraUiHistoryEntry {
13
+ readonly state: LegacyCeraUiMutationState;
14
+ readonly at: number;
15
+ readonly detail?: string;
16
+ }
17
+ /** One CeraUI slot document, decoded verbatim. `preState` is kept opaque. */
18
+ export interface LegacyCeraUiMutationEntry {
19
+ readonly version: typeof LEGACY_CERAUI_JOURNAL_VERSION;
20
+ readonly stableKey: string;
21
+ readonly kind: string;
22
+ readonly state: LegacyCeraUiMutationState;
23
+ readonly attemptId: string;
24
+ readonly startedAt: number;
25
+ readonly updatedAt: number;
26
+ /** The rollback target. Opaque by design — its shape is the mutation kind's. */
27
+ readonly preState: Readonly<Record<string, unknown>>;
28
+ readonly detail?: string;
29
+ readonly acknowledgedMode?: LegacyCeraUiAckMode;
30
+ readonly history: readonly LegacyCeraUiHistoryEntry[];
31
+ }
32
+ export interface LegacyCeraUiJournalRead {
33
+ /** The same recovery model `reconstructJournalRecovery` produces. */
34
+ readonly recovery: JournalRecovery;
35
+ /** The decoded slot documents, verbatim, so `preState` survives the read. */
36
+ readonly entries: readonly LegacyCeraUiMutationEntry[];
37
+ }
38
+ export interface LegacyCeraUiJournalOptions {
39
+ /** REQUIRED. The embedding process owns where CeraUI put its journal. */
40
+ readonly dir: string;
41
+ }
42
+ /**
43
+ * The slot filename CeraUI derives from a stable key.
44
+ *
45
+ * RULE-D MIRROR of CeraUI's own helper. It is a plain lowercase-hex SHA-256 of the
46
+ * key's UTF-8 bytes; the key itself never appears in the filename in plaintext.
47
+ */
48
+ export declare function legacyMutationSlotName(stableKey: string): string;
49
+ /** Validate one slot document. Throws the codec's metadata-only schema errors. */
50
+ export declare function validateLegacyCeraUiEntry(raw: unknown): LegacyCeraUiMutationEntry;
51
+ /** Decode one slot document's text. Never throws; returns a typed failure. */
52
+ export declare function decodeLegacyCeraUiEntry(text: string): JournalDecodeResult<LegacyCeraUiMutationEntry>;
53
+ /**
54
+ * The descriptor evidence a legacy entry can honestly supply.
55
+ *
56
+ * CeraUI's journal predates `OperationDescriptor`, so there is no descriptor to
57
+ * flatten. Every field below is either a fact the file actually carries (the
58
+ * mutation kind) or an explicit statement that the file carries nothing:
59
+ * `confidence: 'unknown'` rather than a borrowed default, and empty evidence
60
+ * arrays rather than invented profiles. `mutationImpact: 'write'` is a fact, not a
61
+ * guess — CeraUI's file is a MUTATION journal and records nothing else.
62
+ */
63
+ export declare function legacyDescriptorEvidence(kind: string): JournalDescriptorEvidence;
64
+ /** Project one decoded slot onto the shared recovery record model. */
65
+ export declare function legacyOperationRecord(entry: LegacyCeraUiMutationEntry): JournalOperationRecord;
66
+ /**
67
+ * Read a whole CeraUI journal directory.
68
+ *
69
+ * An unreadable or non-conforming slot is reported as damage and LEFT IN PLACE;
70
+ * every readable slot still comes back. That is the same non-truncating contract
71
+ * the native store makes, applied to a directory instead of a file.
72
+ */
73
+ export declare function readLegacyCeraUiJournal(options: LegacyCeraUiJournalOptions): Promise<LegacyCeraUiJournalRead>;