@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
@@ -1,65 +0,0 @@
1
- # D-Bus transport seam
2
-
3
- A minimal internal transport interface over [`@httptoolkit/dbus-native`](https://www.npmjs.com/package/@httptoolkit/dbus-native).
4
- Everything the rest of `@ceralive/modem-control` needs to talk to ModemManager over
5
- D-Bus goes through the `DbusTransport` interface exported by [`index.ts`](./index.ts) —
6
- method calls, signal subscriptions, and reconnect. The A3.x D-Bus backend builds
7
- directly on this shape.
8
-
9
- ## Why this library
10
-
11
- `@httptoolkit/dbus-native` is a pure-JavaScript D-Bus client (no libdbus / native
12
- addon), which is the deciding factor: it imports and runs under **Bun 1.3.14** with
13
- **EXTERNAL** auth on a session bus — session-verified during A2.4, and pinned exactly at
14
- `0.1.5`. A native-addon client (anything binding libdbus) is a portability and
15
- cross-compile liability for the arm64 + amd64 device image; a pure-JS client is not.
16
-
17
- ## The fallback
18
-
19
- If `@httptoolkit/dbus-native` proves inadequate — an un-fixable marshalling bug, an
20
- unmaintained upstream, or a Bun incompatibility introduced by a future runtime bump —
21
- the documented fallback is [`@particle/dbus-next`](https://www.npmjs.com/package/@particle/dbus-next),
22
- which is also pure-JS and was verified importable under Bun during planning (draft
23
- ledger §dbus-native). It is **not** implemented here; this note records the escape hatch.
24
- Because the entire library surface is quarantined behind this seam (see below), swapping
25
- to it would touch only [`dbus-native.ts`](./dbus-native.ts), [`transport.ts`](./transport.ts),
26
- and [`codec.ts`](./codec.ts) — never a caller.
27
-
28
- ## The seam contract
29
-
30
- * **No library types leak.** `index.ts` re-exports only the transport's own types
31
- (`DbusValue`, `DbusVariant`, `MethodCall`, `SignalEvent`, …). The raw library types
32
- live in [`dbus-native.ts`](./dbus-native.ts) and go no further. A guard test asserts
33
- the package entry (`../index.ts`) never re-exports the library.
34
- * **Lossless 64-bit.** D-Bus `x` (INT64) and `t` (UINT64) are `bigint` end-to-end, never
35
- a JS `number`. On decode the library runs with `ReturnLongjs: true` and we convert its
36
- Long.js objects to `bigint` via their exact decimal string; on encode we require a
37
- `bigint` and hand the library a decimal string (its only lossless 64-bit input).
38
- Passing a `number` for a 64-bit field throws `BigIntRequiredError`.
39
- * **`h` is unsupported.** UNIX_FD / file-descriptor passing is rejected up front with a
40
- typed `UnsupportedSignatureError` — in an outgoing signature, a reply/signal signature,
41
- or nested in a variant — never silently dropped or coerced.
42
- * **Variants round-trip.** A decoded variant keeps its inner signature
43
- (`DbusVariant { signature, value }`), so encode/decode is symmetric.
44
-
45
- ## Conformance
46
-
47
- Tests run under `dbus-run-session -- bun test control/src/transport` and prove the seam
48
- two independent ways:
49
-
50
- 1. **Same library** ([`conformance-same-lib.test.ts`](./conformance-same-lib.test.ts)) —
51
- round-trips representative signatures against a minimal fake service built on the same
52
- `@httptoolkit/dbus-native`.
53
- 2. **Independent producer** ([`conformance-python.test.ts`](./conformance-python.test.ts)) —
54
- round-trips against a `python3-dbus` (`dbus-python`) service in a subprocess,
55
- exercising `a{oa{sa{sv}}}`, `x`/`t` above 2^53, variants, and `PropertiesChanged`
56
- invalidations. A different implementation on the wire is the real proof our codec is
57
- correct, not merely self-consistent.
58
-
59
- Plus [`reliability.test.ts`](./reliability.test.ts): reconnect after a bus restart
60
- (against a dedicated private `dbus-daemon`), a ≥5000-event signal stream, late replies,
61
- and a 100-cycle subscribe/unsubscribe listener-leak check.
62
-
63
- The `test-support/` fakes here are intentionally minimal — just enough to round-trip the
64
- signatures under test. The MM-faithful fake service (root ObjectManager, `Modem` /
65
- `Modem3gpp` interfaces, SIM objects, bearer tripwires) is a separate, later task (A2.3).
@@ -1,113 +0,0 @@
1
- // Method-call dispatch and reply correlation for the D-Bus transport seam.
2
- //
3
- // A call marshals its body through the codec, registers a pending record so a bus drop can
4
- // reject it, and installs a per-call reply callback guarded by a `done` flag — so a reply
5
- // that arrives after the call already timed out or the connection dropped is silently
6
- // ignored rather than mis-correlated onto a stale promise. `rejectAll` mass-rejects every
7
- // in-flight call when the connection drops.
8
-
9
- import { decodeBody, encodeBody } from './codec';
10
- import { messageType, type RawBus, type RawMessage, type ReplyContext } from './dbus-native';
11
- import { DisconnectedError, TransportError } from './errors';
12
- import type { DbusValue, MethodCall, MethodReply } from './types';
13
-
14
- export const DEFAULT_CALL_TIMEOUT_MS = 30_000;
15
-
16
- interface PendingCall {
17
- settle(): void;
18
- reject(error: unknown): void;
19
- }
20
-
21
- export class CallDispatcher {
22
- readonly #pending = new Set<PendingCall>();
23
- readonly #callTimeoutMs: number;
24
-
25
- constructor(callTimeoutMs: number) {
26
- this.#callTimeoutMs = callTimeoutMs;
27
- }
28
-
29
- async call(bus: RawBus | null, connected: boolean, call: MethodCall): Promise<MethodReply> {
30
- if (!connected || bus === null) {
31
- throw new DisconnectedError('cannot call method: transport not connected');
32
- }
33
-
34
- const signature = call.signature ?? '';
35
- const args = call.args ?? [];
36
- const message: RawMessage = {
37
- type: messageType.methodCall,
38
- destination: call.destination,
39
- path: call.path,
40
- interface: call.interface,
41
- member: call.member,
42
- };
43
- if (signature.length > 0) {
44
- // Throws UnsupportedSignatureError / BigIntRequiredError before anything hits
45
- // the wire.
46
- message.signature = signature;
47
- message.body = encodeBody(signature, args);
48
- }
49
-
50
- const timeoutMs = call.timeoutMs ?? this.#callTimeoutMs;
51
- const pendingSet = this.#pending;
52
- return new Promise<MethodReply>((resolve, reject) => {
53
- let done = false;
54
- const pending: PendingCall = {
55
- settle: finish,
56
- reject: (error) => {
57
- finish();
58
- reject(error);
59
- },
60
- };
61
-
62
- function finish(): void {
63
- if (done) {
64
- return;
65
- }
66
- done = true;
67
- clearTimeout(timer);
68
- pendingSet.delete(pending);
69
- }
70
-
71
- const timer = setTimeout(() => {
72
- finish();
73
- reject(
74
- new TransportError(
75
- `Method call ${call.interface}.${call.member} timed out after ${timeoutMs}ms`,
76
- ),
77
- );
78
- }, timeoutMs);
79
-
80
- pendingSet.add(pending);
81
-
82
- bus.invoke(
83
- message,
84
- function reply(this: ReplyContext, error: unknown, ...body: unknown[]): void {
85
- if (done) {
86
- // Reply arrived after timeout/disconnect already settled the promise — ignore.
87
- return;
88
- }
89
- finish();
90
- if (error) {
91
- reject(error instanceof Error ? error : new TransportError(String(error)));
92
- return;
93
- }
94
- try {
95
- const replySignature = this.signature ?? '';
96
- const decoded: DbusValue[] =
97
- replySignature.length > 0 ? decodeBody(replySignature, body) : [];
98
- resolve({ signature: replySignature, body: decoded });
99
- } catch (decodeError) {
100
- reject(decodeError);
101
- }
102
- },
103
- );
104
- });
105
- }
106
-
107
- rejectAll(cause: unknown): void {
108
- for (const pending of this.#pending) {
109
- pending.reject(cause);
110
- }
111
- this.#pending.clear();
112
- }
113
- }
@@ -1,260 +0,0 @@
1
- // Characterization tests for the transport seam's reconnect / call-correlation / ordering
2
- // edges — the behaviour that a later refactor (splitting transport.ts into lifecycle,
3
- // call-dispatch, and signal modules) MUST preserve byte-for-byte at the observable level.
4
- //
5
- // These pin CURRENT behaviour, not aspirational behaviour: each assertion records what the
6
- // unsplit transport.ts actually does today. If the split changes any of these observable
7
- // facts, one of these tests goes red — which is the whole point.
8
- //
9
- // Like reliability.test.ts, these run against dedicated private `dbus-daemon` instances
10
- // (each test owns one) so a destructive kill/restart is safe. That also makes the file
11
- // self-contained — it needs no outer `dbus-run-session`.
12
-
13
- import { describe, expect, test } from 'bun:test';
14
- import { createDbusTransport } from './index';
15
- import { FAKE_IFACE, FAKE_PATH, startFakeService, TICK_MEMBER } from './test-support/fake-service';
16
- import { PrivateBus } from './test-support/private-bus';
17
-
18
- const HAS_DBUS_DAEMON = Bun.which('dbus-daemon') !== null;
19
-
20
- const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
21
-
22
- async function waitFor(predicate: () => boolean, timeoutMs: number, label: string): Promise<void> {
23
- const deadline = Date.now() + timeoutMs;
24
- while (Date.now() < deadline) {
25
- if (predicate()) {
26
- return;
27
- }
28
- await sleep(10);
29
- }
30
- throw new Error(`timed out after ${timeoutMs}ms waiting for ${label}`);
31
- }
32
-
33
- const tickSpec = { interface: FAKE_IFACE, member: TICK_MEMBER, path: FAKE_PATH };
34
-
35
- describe.skipIf(!HAS_DBUS_DAEMON)('transport characterization', () => {
36
- // (i) A call that times out, then the real reply lands AFTER the timeout already
37
- // settled the promise. The late reply must be silently ignored (each `bus.invoke`
38
- // owns its own reply closure, guarded by a `done` flag) — no crash, and no
39
- // mis-correlation onto a later, unrelated call.
40
- test('a reply arriving after the call already timed out is silently ignored', async () => {
41
- const bus = new PrivateBus();
42
- await bus.start();
43
- const fake = await startFakeService({ socket: bus.socket });
44
- const transport = createDbusTransport({ socket: bus.socket, reconnect: { enabled: false } });
45
- let errorEvents = 0;
46
- transport.on('error', () => {
47
- errorEvents += 1;
48
- });
49
- await transport.connect();
50
-
51
- // SlowPing replies after 400ms; the call's own timeout is 100ms, so it times out
52
- // first and the reply becomes a "late" one 300ms later.
53
- await expect(
54
- transport.callMethod({
55
- destination: fake.busName,
56
- path: FAKE_PATH,
57
- interface: FAKE_IFACE,
58
- member: 'SlowPing',
59
- signature: 'u',
60
- args: [400],
61
- timeoutMs: 100,
62
- }),
63
- ).rejects.toThrow('timed out after 100ms');
64
-
65
- // Wait well past the 400ms reply so the ignored late reply has actually been
66
- // delivered to (and dropped by) the settled callback.
67
- await sleep(500);
68
-
69
- // No crash, no error event, still connected — the late reply disturbed nothing.
70
- expect(errorEvents).toBe(0);
71
- expect(transport.isConnected()).toBe(true);
72
-
73
- // And the pending machinery is intact: a fresh call correlates to its OWN reply,
74
- // proving the late reply was not mis-delivered to a later promise.
75
- const reply = await transport.callMethod({
76
- destination: fake.busName,
77
- path: FAKE_PATH,
78
- interface: FAKE_IFACE,
79
- member: 'Ping',
80
- });
81
- expect(reply.body[0]).toBe('pong');
82
-
83
- await transport.disconnect();
84
- await fake.stop();
85
- await bus.stop();
86
- });
87
-
88
- // (ii) A bus drop while a call is in flight. The in-flight call must reject, and the
89
- // observed ordering is pinned: the `disconnected` event is delivered BEFORE the call
90
- // rejection is observed. (In `#handleDrop`, pending calls are rejected and then
91
- // `disconnected` is emitted synchronously — but a promise rejection is observed on a
92
- // microtask, so the synchronous event listener runs first.)
93
- test('a mid-call bus drop rejects the in-flight call after emitting disconnected', async () => {
94
- const bus = new PrivateBus();
95
- await bus.start();
96
- const fake = await startFakeService({ socket: bus.socket });
97
- const transport = createDbusTransport({ socket: bus.socket, reconnect: { enabled: false } });
98
-
99
- const order: string[] = [];
100
- let rejection: unknown = null;
101
- transport.on('disconnected', () => order.push('disconnected'));
102
- await transport.connect();
103
-
104
- // A call that will never get a reply — the bus dies under it.
105
- const call = transport
106
- .callMethod({
107
- destination: fake.busName,
108
- path: FAKE_PATH,
109
- interface: FAKE_IFACE,
110
- member: 'SlowPing',
111
- signature: 'u',
112
- args: [5000],
113
- })
114
- .catch((error: unknown) => {
115
- order.push('call-rejected');
116
- rejection = error;
117
- });
118
-
119
- // Give the call time to reach the wire, then drop the bus under it.
120
- await sleep(30);
121
- bus.kill();
122
-
123
- await waitFor(
124
- () => order.includes('disconnected') && order.includes('call-rejected'),
125
- 5000,
126
- 'disconnected + call rejection',
127
- );
128
- await call;
129
-
130
- // Pinned ordering: the event precedes the observed rejection.
131
- expect(order).toEqual(['disconnected', 'call-rejected']);
132
- // Pinned rejection type: a DisconnectedError (the connection-end drop cause).
133
- expect(rejection).toBeInstanceOf(Error);
134
- expect((rejection as Error).name).toBe('DisconnectedError');
135
-
136
- await transport.disconnect();
137
- // The fake died with its bus; stopping it would write to a closed stream. Leave it.
138
- await bus.stop();
139
- });
140
-
141
- // (iii) A drop that arrives while a reconnect is already running. The reconnect loop is
142
- // idempotent: `#handleDrop` early-returns whenever the state is already `disconnected`
143
- // or `reconnecting`, so repeated low-level drop signals never spawn a second reconnect
144
- // loop. The transport converges to a single connected state — exactly one `disconnected`
145
- // and one `reconnected`, no error, and it is not wedged.
146
- test('a drop during an in-flight reconnect does not double-schedule or wedge', async () => {
147
- const bus = new PrivateBus();
148
- await bus.start();
149
- let fake = await startFakeService({ socket: bus.socket });
150
- const transport = createDbusTransport({
151
- socket: bus.socket,
152
- reconnect: { initialDelayMs: 25, maxDelayMs: 100 },
153
- });
154
-
155
- const events: string[] = [];
156
- let errorEvents = 0;
157
- transport.on('disconnected', () => events.push('disconnected'));
158
- transport.on('reconnected', () => events.push('reconnected'));
159
- transport.on('error', () => {
160
- errorEvents += 1;
161
- });
162
- await transport.connect();
163
-
164
- const ticks: bigint[] = [];
165
- const subscription = await transport.subscribeSignal(tickSpec, (event) => {
166
- ticks.push(event.body[0] as bigint);
167
- });
168
-
169
- fake.emitTick(11n);
170
- await waitFor(() => ticks.includes(11n), 3000, 'pre-drop tick');
171
-
172
- // Drop the bus and leave it down long enough for the reconnect loop to spin through
173
- // several failed establish attempts before the bus returns.
174
- bus.kill();
175
- await waitFor(() => events.includes('disconnected'), 5000, 'disconnected');
176
- await sleep(150);
177
- await bus.start();
178
- await waitFor(() => events.includes('reconnected'), 15000, 'reconnected');
179
-
180
- // A settle window to catch any spurious extra event from a double-scheduled loop.
181
- await sleep(300);
182
-
183
- expect(events.filter((event) => event === 'disconnected')).toHaveLength(1);
184
- expect(events.filter((event) => event === 'reconnected')).toHaveLength(1);
185
- expect(errorEvents).toBe(0);
186
-
187
- // Not wedged: a fresh producer's signal flows through the auto-resubscribed rule.
188
- fake = await startFakeService({ socket: bus.socket });
189
- fake.emitTick(22n);
190
- await waitFor(() => ticks.includes(22n), 8000, 'post-reconnect tick');
191
- expect(transport.subscriptionCount()).toBe(1);
192
-
193
- await subscription.unsubscribe();
194
- await transport.disconnect();
195
- await fake.stop();
196
- await bus.stop();
197
- }, 30000);
198
-
199
- // (iv) A subscription added AND one removed while a reconnect is in progress. Because
200
- // mutating a subscription while disconnected only touches the in-memory match-rule
201
- // refcount (the bus call is skipped when not connected), and `#establish()` re-issues
202
- // every live rule on reconnect, the refcounting must end up correct: the added
203
- // subscription is registered (receives signals) and the removed one is not.
204
- test('subscriptions mutated during reconnect end up correctly (un)registered', async () => {
205
- const bus = new PrivateBus();
206
- await bus.start();
207
- const transport = createDbusTransport({
208
- socket: bus.socket,
209
- reconnect: { initialDelayMs: 25, maxDelayMs: 100 },
210
- });
211
-
212
- const events: string[] = [];
213
- transport.on('disconnected', () => events.push('disconnected'));
214
- transport.on('reconnected', () => events.push('reconnected'));
215
- await transport.connect();
216
-
217
- // `removed` is a path-filtered rule; `added` is a distinct (no-path) rule that still
218
- // matches the same emitted Tick — so their match-rule strings differ and are tracked
219
- // independently.
220
- const removedTicks: bigint[] = [];
221
- const addedTicks: bigint[] = [];
222
- const removed = await transport.subscribeSignal(tickSpec, (event) => {
223
- removedTicks.push(event.body[0] as bigint);
224
- });
225
- expect(transport.subscriptionCount()).toBe(1);
226
-
227
- // Drop the bus; while the reconnect loop is running, mutate the subscription set.
228
- bus.kill();
229
- await waitFor(() => events.includes('disconnected'), 5000, 'disconnected');
230
-
231
- await removed.unsubscribe();
232
- const added = await transport.subscribeSignal(
233
- { interface: FAKE_IFACE, member: TICK_MEMBER },
234
- (event) => {
235
- addedTicks.push(event.body[0] as bigint);
236
- },
237
- );
238
- expect(transport.subscriptionCount()).toBe(1);
239
-
240
- // Bring the bus back; `#establish()` re-issues exactly the rules still in the
241
- // refcount map — the `added` one, not the `removed` one.
242
- await bus.start();
243
- await waitFor(() => events.includes('reconnected'), 15000, 'reconnected');
244
-
245
- const fake = await startFakeService({ socket: bus.socket });
246
- fake.emitTick(33n);
247
- await waitFor(() => addedTicks.includes(33n), 8000, 'added-subscription tick');
248
-
249
- // Grace to prove the removed subscription genuinely receives nothing.
250
- await sleep(200);
251
- expect(addedTicks).toEqual([33n]);
252
- expect(removedTicks).toEqual([]);
253
- expect(transport.subscriptionCount()).toBe(1);
254
-
255
- await added.unsubscribe();
256
- await transport.disconnect();
257
- await fake.stop();
258
- await bus.stop();
259
- }, 30000);
260
- });
@@ -1,118 +0,0 @@
1
- // Pure, in-process encode/decode round-trip: no bus, fully deterministic. Marshals with
2
- // the library's own marshaller and reads it back with its DBusBuffer under
3
- // `ReturnLongjs: true` — exactly the wire path a real call takes — so a green run here is
4
- // exact proof the codec is lossless, independent of any daemon timing.
5
-
6
- import { expect, test } from 'bun:test';
7
- import DBusBuffer from '@httptoolkit/dbus-native/lib/dbus-buffer';
8
- import marshall from '@httptoolkit/dbus-native/lib/marshall';
9
- import { decodeBody, encodeBody } from './codec';
10
- import { BigIntRequiredError, SixtyFourBitRangeError, UnsupportedSignatureError } from './errors';
11
- import { type DbusValue, variant } from './types';
12
-
13
- const INT64_MAX = 2n ** 63n - 1n;
14
- const INT64_MIN = -(2n ** 63n);
15
- const UINT64_MAX = 2n ** 64n - 1n;
16
-
17
- function roundTrip(signature: string, values: readonly DbusValue[]): DbusValue[] {
18
- const encoded = encodeBody(signature, values);
19
- const buffer = marshall(signature, encoded);
20
- const reader = new DBusBuffer(buffer, 0, { ayBuffer: true, ReturnLongjs: true });
21
- const raw = reader.read(signature) as unknown[];
22
- return decodeBody(signature, raw);
23
- }
24
-
25
- test('2^63-1 round-trips through an INT64 exactly (bigint equality)', () => {
26
- const [value] = roundTrip('x', [INT64_MAX]);
27
- expect(value).toBe(INT64_MAX);
28
- expect(typeof value).toBe('bigint');
29
- });
30
-
31
- test('the full UINT64 range (2^64-1) round-trips exactly', () => {
32
- const [value] = roundTrip('t', [UINT64_MAX]);
33
- expect(value).toBe(UINT64_MAX);
34
- });
35
-
36
- test('INT64 minimum round-trips exactly', () => {
37
- const [value] = roundTrip('x', [INT64_MIN]);
38
- expect(value).toBe(INT64_MIN);
39
- });
40
-
41
- test('a value just above 2^53 survives (no silent Number coercion)', () => {
42
- const beyondSafe = 2n ** 53n + 1n;
43
- const [asInt, asUint] = roundTrip('xt', [beyondSafe, beyondSafe]);
44
- expect(asInt).toBe(beyondSafe);
45
- expect(asUint).toBe(beyondSafe);
46
- // The precision-losing path would have produced 9007199254740992n (== 2^53).
47
- expect(asInt).not.toBe(2n ** 53n);
48
- });
49
-
50
- test('the MM GetManagedObjects shape a{oa{sa{sv}}} round-trips with a 64-bit variant', () => {
51
- const managed: DbusValue = [
52
- [
53
- '/org/freedesktop/ModemManager1/Modem/0',
54
- [
55
- [
56
- 'org.freedesktop.ModemManager1.Modem',
57
- [
58
- ['SupportedCapabilities', variant('t', UINT64_MAX)],
59
- ['SignalQuality', variant('u', 87)],
60
- ['DeviceIdentifier', variant('s', 'dev-0')],
61
- ],
62
- ],
63
- ],
64
- ],
65
- ];
66
- const [decoded] = roundTrip('a{oa{sa{sv}}}', [managed]);
67
- expect(decoded).toEqual(managed);
68
- });
69
-
70
- test('a variant preserves its inner signature and 64-bit value across a round-trip', () => {
71
- const [decoded] = roundTrip('v', [variant('t', UINT64_MAX)]);
72
- expect(decoded).toEqual({ signature: 't', value: UINT64_MAX });
73
- });
74
-
75
- test('a byte array (ay) round-trips as a Uint8Array', () => {
76
- const bytes = new Uint8Array([0, 1, 2, 254, 255]);
77
- const [decoded] = roundTrip('ay', [bytes]);
78
- expect(decoded).toBeInstanceOf(Uint8Array);
79
- expect(Array.from(decoded as Uint8Array)).toEqual([0, 1, 2, 254, 255]);
80
- });
81
-
82
- test('a struct with mixed 64-bit fields round-trips', () => {
83
- const [decoded] = roundTrip('(xtu)', [[INT64_MIN, UINT64_MAX, 7]]);
84
- expect(decoded).toEqual([INT64_MIN, UINT64_MAX, 7]);
85
- });
86
-
87
- test('signature h (UNIX_FD) is rejected on encode with a typed error', () => {
88
- expect(() => encodeBody('h', [0])).toThrow(UnsupportedSignatureError);
89
- });
90
-
91
- test('signature h nested inside a container is rejected on encode', () => {
92
- expect(() => encodeBody('a{sh}', [[]])).toThrow(UnsupportedSignatureError);
93
- });
94
-
95
- test('signature h is rejected on decode with a typed error', () => {
96
- expect(() => decodeBody('h', [0])).toThrow(UnsupportedSignatureError);
97
- });
98
-
99
- test('the UnsupportedSignatureError carries the offending type', () => {
100
- try {
101
- encodeBody('h', [0]);
102
- throw new Error('expected throw');
103
- } catch (error) {
104
- expect(error).toBeInstanceOf(UnsupportedSignatureError);
105
- expect((error as UnsupportedSignatureError).unsupportedType).toBe('h');
106
- }
107
- });
108
-
109
- test('passing a JS number for a 64-bit field throws BigIntRequiredError', () => {
110
- expect(() => encodeBody('t', [123])).toThrow(BigIntRequiredError);
111
- expect(() => encodeBody('x', [123])).toThrow(BigIntRequiredError);
112
- });
113
-
114
- test('an out-of-range 64-bit bigint throws SixtyFourBitRangeError', () => {
115
- expect(() => encodeBody('t', [-1n])).toThrow(SixtyFourBitRangeError);
116
- expect(() => encodeBody('x', [2n ** 63n])).toThrow(SixtyFourBitRangeError);
117
- expect(() => encodeBody('t', [2n ** 64n])).toThrow(SixtyFourBitRangeError);
118
- });