@ceralive/modem-control 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +341 -0
  2. package/dist/backend/at-lease.d.ts +59 -0
  3. package/dist/backend/at-lease.js +118 -0
  4. package/dist/backend/cell-info.d.ts +46 -0
  5. package/dist/backend/cell-info.js +124 -0
  6. package/dist/backend/constants.d.ts +24 -0
  7. package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
  8. package/dist/backend/device-classifier.d.ts +46 -0
  9. package/dist/backend/device-classifier.js +258 -0
  10. package/dist/backend/enrichment.d.ts +28 -0
  11. package/dist/backend/enrichment.js +59 -0
  12. package/dist/backend/features.d.ts +61 -0
  13. package/dist/backend/features.js +109 -0
  14. package/dist/backend/identity-ladder.d.ts +57 -0
  15. package/dist/backend/identity-ladder.js +158 -0
  16. package/dist/backend/identity-registry.d.ts +51 -0
  17. package/dist/backend/identity-registry.js +101 -0
  18. package/dist/backend/index.d.ts +30 -0
  19. package/dist/backend/index.js +35 -0
  20. package/dist/backend/lifecycle-interlock.d.ts +25 -0
  21. package/dist/backend/lifecycle-interlock.js +18 -0
  22. package/dist/backend/managed-objects.d.ts +39 -0
  23. package/dist/backend/managed-objects.js +82 -0
  24. package/dist/backend/mapping.d.ts +11 -0
  25. package/dist/backend/mapping.js +148 -0
  26. package/dist/backend/mm-backend.d.ts +44 -0
  27. package/dist/backend/mm-backend.js +154 -0
  28. package/dist/backend/mm-location.d.ts +21 -0
  29. package/dist/backend/mm-location.js +237 -0
  30. package/dist/backend/mm-mutations.d.ts +42 -0
  31. package/dist/backend/mm-mutations.js +259 -0
  32. package/dist/backend/modem-actor.d.ts +41 -0
  33. package/dist/backend/modem-actor.js +78 -0
  34. package/dist/backend/nm-auto-apn.d.ts +54 -0
  35. package/dist/backend/nm-auto-apn.js +124 -0
  36. package/dist/backend/nm-gsm-fields.d.ts +23 -0
  37. package/dist/backend/nm-gsm-fields.js +107 -0
  38. package/dist/backend/nmcli-nm-port.d.ts +28 -0
  39. package/dist/backend/nmcli-nm-port.js +173 -0
  40. package/dist/backend/nmcli-runner.d.ts +24 -0
  41. package/dist/backend/nmcli-runner.js +35 -0
  42. package/dist/backend/observer.d.ts +37 -0
  43. package/dist/backend/observer.js +219 -0
  44. package/dist/backend/power-contract.d.ts +49 -0
  45. package/dist/backend/power-contract.js +34 -0
  46. package/dist/backend/recovery-attribution.d.ts +32 -0
  47. package/dist/backend/recovery-attribution.js +57 -0
  48. package/dist/backend/recovery-budget.d.ts +45 -0
  49. package/dist/backend/recovery-budget.js +44 -0
  50. package/dist/backend/recovery-ladder.d.ts +94 -0
  51. package/dist/backend/recovery-ladder.js +116 -0
  52. package/dist/backend/router-ethernet.d.ts +19 -0
  53. package/dist/backend/router-ethernet.js +66 -0
  54. package/dist/backend/row-store.d.ts +13 -0
  55. package/dist/backend/row-store.js +82 -0
  56. package/dist/backend/signal-setup.d.ts +30 -0
  57. package/dist/backend/signal-setup.js +92 -0
  58. package/dist/backend/sim-unlock.d.ts +13 -0
  59. package/dist/backend/sim-unlock.js +153 -0
  60. package/dist/backend/transition-preconditions.d.ts +101 -0
  61. package/dist/backend/transition-preconditions.js +132 -0
  62. package/dist/backend/usage/accounting.d.ts +39 -0
  63. package/dist/backend/usage/accounting.js +73 -0
  64. package/dist/backend/usage/billing-cycle.d.ts +11 -0
  65. package/dist/backend/usage/billing-cycle.js +39 -0
  66. package/dist/backend/usage/boot-id.d.ts +6 -0
  67. package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
  68. package/dist/backend/usage/index.d.ts +8 -0
  69. package/dist/backend/usage/index.js +11 -0
  70. package/dist/backend/usage/policy-store.d.ts +50 -0
  71. package/dist/backend/usage/policy-store.js +161 -0
  72. package/dist/backend/usage/policy-write.d.ts +65 -0
  73. package/dist/backend/usage/policy-write.js +112 -0
  74. package/dist/backend/usage/proc-net-dev.d.ts +18 -0
  75. package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
  76. package/dist/backend/usage/sampler.d.ts +75 -0
  77. package/dist/backend/usage/sampler.js +211 -0
  78. package/dist/backend/usage/store.d.ts +38 -0
  79. package/dist/backend/usage/store.js +126 -0
  80. package/dist/backend/usb-device-snapshot.d.ts +31 -0
  81. package/dist/backend/usb-device-snapshot.js +1 -0
  82. package/dist/backend/usb-enumerator.d.ts +21 -0
  83. package/dist/backend/usb-enumerator.js +153 -0
  84. package/dist/backend/usb-mode-transition.d.ts +29 -0
  85. package/dist/backend/usb-mode-transition.js +216 -0
  86. package/dist/band/band-names.d.ts +42 -0
  87. package/dist/band/band-names.js +150 -0
  88. package/dist/band/certification.d.ts +84 -0
  89. package/dist/band/certification.js +127 -0
  90. package/dist/band/certified-bands.json +4 -0
  91. package/dist/band/index.d.ts +2 -0
  92. package/dist/band/index.js +8 -0
  93. package/dist/capability/detect.d.ts +52 -0
  94. package/dist/capability/detect.js +86 -0
  95. package/dist/capability/five-g-preference.d.ts +104 -0
  96. package/dist/capability/five-g-preference.js +171 -0
  97. package/dist/capability/index.d.ts +3 -0
  98. package/dist/capability/index.js +10 -0
  99. package/dist/capability/support-claim.d.ts +39 -0
  100. package/dist/capability/support-claim.js +81 -0
  101. package/dist/domain/brand.d.ts +10 -0
  102. package/dist/domain/brand.js +21 -0
  103. package/dist/domain/errors.d.ts +32 -0
  104. package/dist/domain/errors.js +48 -0
  105. package/dist/domain/generation.d.ts +8 -0
  106. package/dist/domain/generation.js +12 -0
  107. package/dist/domain/guards.d.ts +6 -0
  108. package/dist/domain/guards.js +127 -0
  109. package/dist/domain/identity.d.ts +109 -0
  110. package/dist/domain/identity.js +86 -0
  111. package/dist/domain/index.d.ts +14 -0
  112. package/dist/domain/index.js +18 -0
  113. package/dist/domain/mm-enums.d.ts +12 -0
  114. package/dist/domain/mm-enums.js +139 -0
  115. package/dist/domain/modem-presentation.d.ts +10 -0
  116. package/dist/domain/modem-presentation.js +39 -0
  117. package/dist/domain/observation.d.ts +39 -0
  118. package/dist/domain/observation.js +4 -0
  119. package/dist/domain/operation.d.ts +118 -0
  120. package/dist/domain/operation.js +85 -0
  121. package/dist/domain/physical-identity.d.ts +43 -0
  122. package/dist/domain/physical-identity.js +113 -0
  123. package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
  124. package/dist/domain/policy.js +38 -0
  125. package/dist/domain/shadow-divergence.d.ts +27 -0
  126. package/dist/domain/shadow-divergence.js +70 -0
  127. package/dist/domain/snapshot.d.ts +53 -0
  128. package/dist/domain/snapshot.js +75 -0
  129. package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
  130. package/dist/domain/state.js +38 -0
  131. package/dist/fcc/coverage.d.ts +63 -0
  132. package/dist/fcc/coverage.js +102 -0
  133. package/dist/fcc/index.d.ts +3 -0
  134. package/dist/fcc/index.js +12 -0
  135. package/dist/fcc/policy-store.d.ts +40 -0
  136. package/dist/fcc/policy-store.js +146 -0
  137. package/dist/fcc/policy-write.d.ts +32 -0
  138. package/dist/fcc/policy-write.js +37 -0
  139. package/dist/hardware/hilink-protocol.d.ts +39 -0
  140. package/dist/hardware/hilink-protocol.js +58 -0
  141. package/dist/hardware/index.d.ts +3 -0
  142. package/dist/hardware/index.js +15 -0
  143. package/dist/hardware/router-parsers.d.ts +89 -0
  144. package/dist/hardware/router-parsers.js +234 -0
  145. package/dist/index.d.ts +20 -0
  146. package/dist/index.js +27 -0
  147. package/dist/journal/codec.d.ts +44 -0
  148. package/dist/journal/codec.js +198 -0
  149. package/dist/journal/engine.d.ts +28 -0
  150. package/dist/journal/engine.js +68 -0
  151. package/dist/journal/entry.d.ts +74 -0
  152. package/dist/journal/entry.js +56 -0
  153. package/dist/journal/index.d.ts +6 -0
  154. package/dist/journal/index.js +6 -0
  155. package/dist/journal/legacy-ceraui.d.ts +73 -0
  156. package/dist/journal/legacy-ceraui.js +227 -0
  157. package/dist/journal/recovery.d.ts +58 -0
  158. package/dist/journal/recovery.js +117 -0
  159. package/dist/journal/store.d.ts +55 -0
  160. package/dist/journal/store.js +150 -0
  161. package/dist/location/fix-state.d.ts +53 -0
  162. package/dist/location/fix-state.js +75 -0
  163. package/dist/location/index.d.ts +2 -0
  164. package/dist/location/index.js +8 -0
  165. package/dist/location/nmea.d.ts +10 -0
  166. package/dist/location/nmea.js +89 -0
  167. package/dist/observations/envelope.d.ts +63 -0
  168. package/dist/observations/envelope.js +77 -0
  169. package/dist/observations/freshness.d.ts +28 -0
  170. package/dist/observations/freshness.js +76 -0
  171. package/dist/observations/index.d.ts +13 -0
  172. package/dist/observations/index.js +24 -0
  173. package/dist/observations/metric.d.ts +61 -0
  174. package/dist/observations/metric.js +73 -0
  175. package/dist/observations/model.d.ts +80 -0
  176. package/dist/observations/model.js +11 -0
  177. package/dist/observations/provenance.d.ts +94 -0
  178. package/dist/observations/provenance.js +67 -0
  179. package/dist/observations/raw.d.ts +42 -0
  180. package/dist/observations/raw.js +146 -0
  181. package/dist/observations/reading.d.ts +51 -0
  182. package/dist/observations/reading.js +65 -0
  183. package/dist/observations/sources/hilink.d.ts +10 -0
  184. package/dist/observations/sources/hilink.js +84 -0
  185. package/dist/observations/sources/modemmanager.d.ts +18 -0
  186. package/dist/observations/sources/modemmanager.js +239 -0
  187. package/dist/observations/sources/router-shared.d.ts +29 -0
  188. package/dist/observations/sources/router-shared.js +68 -0
  189. package/dist/observations/sources/ufi.d.ts +10 -0
  190. package/dist/observations/sources/ufi.js +111 -0
  191. package/dist/observations/sources/zte.d.ts +7 -0
  192. package/dist/observations/sources/zte.js +71 -0
  193. package/dist/observations/state-separation.d.ts +64 -0
  194. package/dist/observations/state-separation.js +52 -0
  195. package/dist/operation-ids.d.ts +2 -0
  196. package/dist/operation-ids.js +26 -0
  197. package/dist/operations/contracts.d.ts +72 -0
  198. package/dist/operations/contracts.js +1 -0
  199. package/dist/operations/index.d.ts +1 -0
  200. package/dist/operations/index.js +1 -0
  201. package/dist/operations/operation-engine.d.ts +16 -0
  202. package/dist/operations/operation-engine.js +194 -0
  203. package/dist/ports/index.d.ts +12 -0
  204. package/{src/ports/index.ts → dist/ports/index.js} +12 -8
  205. package/dist/ports/location.d.ts +87 -0
  206. package/dist/ports/location.js +36 -0
  207. package/dist/ports/modem-manager.d.ts +89 -0
  208. package/dist/ports/modem-manager.js +9 -0
  209. package/dist/ports/mutation-admission.d.ts +27 -0
  210. package/dist/ports/mutation-admission.js +9 -0
  211. package/dist/ports/network-manager.d.ts +68 -0
  212. package/dist/ports/network-manager.js +13 -0
  213. package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
  214. package/dist/ports/observation.js +7 -0
  215. package/dist/ports/ops.d.ts +44 -0
  216. package/dist/ports/ops.js +16 -0
  217. package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
  218. package/dist/ports/receipts.js +9 -0
  219. package/dist/ports/reconcile.d.ts +33 -0
  220. package/dist/ports/reconcile.js +200 -0
  221. package/dist/ports/resource-ownership.d.ts +29 -0
  222. package/dist/ports/resource-ownership.js +1 -0
  223. package/dist/ports/router.d.ts +19 -0
  224. package/dist/ports/router.js +7 -0
  225. package/dist/ports/sms.d.ts +64 -0
  226. package/dist/ports/sms.js +24 -0
  227. package/dist/ports/uhubctl.d.ts +6 -0
  228. package/dist/ports/uhubctl.js +1 -0
  229. package/dist/providers/contracts.d.ts +124 -0
  230. package/dist/providers/contracts.js +10 -0
  231. package/dist/providers/huawei-hilink/index.d.ts +2 -0
  232. package/dist/providers/huawei-hilink/index.js +2 -0
  233. package/dist/providers/huawei-hilink/operations.d.ts +20 -0
  234. package/dist/providers/huawei-hilink/operations.js +56 -0
  235. package/dist/providers/huawei-hilink/provider.d.ts +52 -0
  236. package/dist/providers/huawei-hilink/provider.js +76 -0
  237. package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
  238. package/dist/providers/huawei-hilink/runtime.js +171 -0
  239. package/dist/providers/huawei-hilink/session.d.ts +28 -0
  240. package/dist/providers/huawei-hilink/session.js +120 -0
  241. package/dist/providers/huawei-hilink/transport.d.ts +19 -0
  242. package/dist/providers/huawei-hilink/transport.js +1 -0
  243. package/dist/providers/index.d.ts +8 -0
  244. package/dist/providers/index.js +8 -0
  245. package/dist/providers/matcher.d.ts +3 -0
  246. package/dist/providers/matcher.js +205 -0
  247. package/dist/providers/modem-manager/errors.d.ts +7 -0
  248. package/dist/providers/modem-manager/errors.js +37 -0
  249. package/dist/providers/modem-manager/generic-operations.d.ts +10 -0
  250. package/dist/providers/modem-manager/generic-operations.js +209 -0
  251. package/dist/providers/modem-manager/index.d.ts +4 -0
  252. package/dist/providers/modem-manager/index.js +4 -0
  253. package/dist/providers/modem-manager/module-operations.d.ts +21 -0
  254. package/dist/providers/modem-manager/module-operations.js +118 -0
  255. package/dist/providers/modem-manager/provider.d.ts +41 -0
  256. package/dist/providers/modem-manager/provider.js +155 -0
  257. package/dist/providers/modem-manager/runtime-composition-operation.d.ts +32 -0
  258. package/dist/providers/modem-manager/runtime-composition-operation.js +151 -0
  259. package/dist/providers/modem-manager/snapshot.d.ts +5 -0
  260. package/dist/providers/modem-manager/snapshot.js +204 -0
  261. package/dist/providers/modem-manager/types.d.ts +137 -0
  262. package/dist/providers/modem-manager/types.js +1 -0
  263. package/dist/providers/network-manager/adapter.d.ts +71 -0
  264. package/dist/providers/network-manager/adapter.js +348 -0
  265. package/dist/providers/network-manager/index.d.ts +2 -0
  266. package/dist/providers/network-manager/index.js +2 -0
  267. package/dist/providers/network-manager/types.d.ts +171 -0
  268. package/dist/providers/network-manager/types.js +77 -0
  269. package/dist/providers/registry.d.ts +13 -0
  270. package/dist/providers/registry.js +33 -0
  271. package/dist/providers/ufi-himi/index.d.ts +6 -0
  272. package/dist/providers/ufi-himi/index.js +6 -0
  273. package/dist/providers/ufi-himi/operations.d.ts +41 -0
  274. package/dist/providers/ufi-himi/operations.js +66 -0
  275. package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
  276. package/dist/providers/ufi-himi/prohibitions.js +88 -0
  277. package/dist/providers/ufi-himi/provider.d.ts +41 -0
  278. package/dist/providers/ufi-himi/provider.js +204 -0
  279. package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
  280. package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
  281. package/dist/providers/ufi-himi/session.d.ts +46 -0
  282. package/dist/providers/ufi-himi/session.js +92 -0
  283. package/dist/providers/ufi-himi/transport.d.ts +29 -0
  284. package/dist/providers/ufi-himi/transport.js +25 -0
  285. package/dist/providers/zte-goform/index.d.ts +2 -0
  286. package/dist/providers/zte-goform/index.js +2 -0
  287. package/dist/providers/zte-goform/provider.d.ts +56 -0
  288. package/dist/providers/zte-goform/provider.js +101 -0
  289. package/dist/providers/zte-goform/session.d.ts +23 -0
  290. package/dist/providers/zte-goform/session.js +197 -0
  291. package/dist/providers/zte-goform/transport.d.ts +16 -0
  292. package/dist/providers/zte-goform/transport.js +1 -0
  293. package/dist/radio/band-truth.d.ts +50 -0
  294. package/dist/radio/band-truth.js +92 -0
  295. package/dist/radio/index.d.ts +3 -0
  296. package/dist/radio/index.js +10 -0
  297. package/dist/radio/mode-combinations.d.ts +88 -0
  298. package/dist/radio/mode-combinations.js +198 -0
  299. package/dist/radio/mode-truth.d.ts +67 -0
  300. package/dist/radio/mode-truth.js +112 -0
  301. package/dist/redact.d.ts +15 -0
  302. package/dist/redact.js +189 -0
  303. package/dist/safety/composition-root.d.ts +28 -0
  304. package/dist/safety/composition-root.js +65 -0
  305. package/dist/safety/flock-resource-ownership.d.ts +11 -0
  306. package/dist/safety/flock-resource-ownership.js +138 -0
  307. package/dist/safety/index.d.ts +2 -0
  308. package/dist/safety/index.js +2 -0
  309. package/dist/sms/dbus-messaging.d.ts +17 -0
  310. package/dist/sms/dbus-messaging.js +185 -0
  311. package/dist/sms/inbox-store.d.ts +10 -0
  312. package/dist/sms/inbox-store.js +82 -0
  313. package/dist/sms/index.d.ts +4 -0
  314. package/dist/sms/index.js +10 -0
  315. package/dist/sms/mmcli-parse.d.ts +54 -0
  316. package/dist/sms/mmcli-parse.js +224 -0
  317. package/dist/sms/normalize.d.ts +42 -0
  318. package/dist/sms/normalize.js +95 -0
  319. package/dist/testing/domain-fakes.d.ts +58 -0
  320. package/dist/testing/domain-fakes.js +98 -0
  321. package/dist/testing/index.d.ts +2 -0
  322. package/dist/testing/index.js +17 -0
  323. package/dist/testing/provider-fakes.d.ts +45 -0
  324. package/dist/testing/provider-fakes.js +64 -0
  325. package/dist/transport/calls.d.ts +9 -0
  326. package/dist/transport/calls.js +88 -0
  327. package/dist/transport/codec.d.ts +3 -0
  328. package/dist/transport/codec.js +207 -0
  329. package/dist/transport/dbus-native.d.ts +57 -0
  330. package/dist/transport/dbus-native.js +17 -0
  331. package/dist/transport/errors.d.ts +21 -0
  332. package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
  333. package/dist/transport/index.d.ts +4 -0
  334. package/dist/transport/index.js +9 -0
  335. package/dist/transport/signals.d.ts +15 -0
  336. package/dist/transport/signals.js +123 -0
  337. package/dist/transport/signature.d.ts +7 -0
  338. package/dist/transport/signature.js +94 -0
  339. package/dist/transport/transport.d.ts +2 -0
  340. package/dist/transport/transport.js +202 -0
  341. package/dist/transport/types.d.ts +61 -0
  342. package/dist/transport/types.js +19 -0
  343. package/dist/usb-mode/catalog-schema.d.ts +139 -0
  344. package/dist/usb-mode/catalog-schema.js +97 -0
  345. package/dist/usb-mode/catalog.d.ts +21 -0
  346. package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
  347. package/dist/usb-mode/certified-catalog.json +67 -0
  348. package/dist/usb-mode/index.d.ts +6 -0
  349. package/dist/usb-mode/index.js +16 -0
  350. package/dist/usb-mode/ingestion.d.ts +111 -0
  351. package/dist/usb-mode/ingestion.js +187 -0
  352. package/dist/usb-mode/promotion-review.d.ts +21 -0
  353. package/dist/usb-mode/promotion-review.js +87 -0
  354. package/dist/usb-mode/runtime-capability.d.ts +59 -0
  355. package/dist/usb-mode/runtime-capability.js +157 -0
  356. package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
  357. package/dist/usb-mode/usb-devices-parse.js +157 -0
  358. package/dist/ussd/calls.d.ts +32 -0
  359. package/dist/ussd/calls.js +96 -0
  360. package/dist/ussd/index.d.ts +5 -0
  361. package/dist/ussd/index.js +12 -0
  362. package/dist/ussd/mm-ussd.d.ts +37 -0
  363. package/dist/ussd/mm-ussd.js +205 -0
  364. package/dist/ussd/refusal.d.ts +53 -0
  365. package/dist/ussd/refusal.js +154 -0
  366. package/dist/ussd/registration.d.ts +20 -0
  367. package/dist/ussd/registration.js +101 -0
  368. package/dist/ussd/session.d.ts +106 -0
  369. package/dist/ussd/session.js +163 -0
  370. package/package.json +38 -4
  371. package/src/backend/at-lease.test.ts +0 -106
  372. package/src/backend/at-lease.ts +0 -158
  373. package/src/backend/cell-info.test.ts +0 -154
  374. package/src/backend/cell-info.ts +0 -160
  375. package/src/backend/device-classifier.test.ts +0 -168
  376. package/src/backend/device-classifier.ts +0 -248
  377. package/src/backend/enrichment.ts +0 -96
  378. package/src/backend/features.test.ts +0 -162
  379. package/src/backend/features.ts +0 -179
  380. package/src/backend/identity-ladder.test.ts +0 -117
  381. package/src/backend/identity-ladder.ts +0 -221
  382. package/src/backend/identity-registry.test.ts +0 -89
  383. package/src/backend/identity-registry.ts +0 -151
  384. package/src/backend/index.ts +0 -236
  385. package/src/backend/lifecycle-interlock.ts +0 -38
  386. package/src/backend/managed-objects.ts +0 -108
  387. package/src/backend/mapping.ts +0 -160
  388. package/src/backend/mm-backend.ts +0 -191
  389. package/src/backend/mm-mutations.ts +0 -228
  390. package/src/backend/modem-actor.test.ts +0 -95
  391. package/src/backend/modem-actor.ts +0 -112
  392. package/src/backend/nm-auto-apn.ts +0 -161
  393. package/src/backend/nm-gsm-fields.ts +0 -122
  394. package/src/backend/nmcli-nm-port.ts +0 -228
  395. package/src/backend/nmcli-runner.ts +0 -52
  396. package/src/backend/observer.ts +0 -297
  397. package/src/backend/power-contract.test.ts +0 -40
  398. package/src/backend/power-contract.ts +0 -83
  399. package/src/backend/recovery-attribution.test.ts +0 -102
  400. package/src/backend/recovery-attribution.ts +0 -86
  401. package/src/backend/recovery-budget.test.ts +0 -64
  402. package/src/backend/recovery-budget.ts +0 -84
  403. package/src/backend/recovery-ladder.test.ts +0 -257
  404. package/src/backend/recovery-ladder.ts +0 -249
  405. package/src/backend/router-ethernet.test.ts +0 -71
  406. package/src/backend/router-ethernet.ts +0 -90
  407. package/src/backend/row-store.ts +0 -105
  408. package/src/backend/signal-setup.ts +0 -112
  409. package/src/backend/sim-unlock.ts +0 -193
  410. package/src/backend/transition-preconditions.ts +0 -149
  411. package/src/backend/uhubctl-power-hook.test.ts +0 -274
  412. package/src/backend/uhubctl-power-hook.ts +0 -377
  413. package/src/backend/usage/accounting.test.ts +0 -147
  414. package/src/backend/usage/accounting.ts +0 -123
  415. package/src/backend/usage/billing-cycle.test.ts +0 -62
  416. package/src/backend/usage/billing-cycle.ts +0 -45
  417. package/src/backend/usage/index.ts +0 -60
  418. package/src/backend/usage/policy-store.test.ts +0 -164
  419. package/src/backend/usage/policy-store.ts +0 -216
  420. package/src/backend/usage/policy-write.test.ts +0 -198
  421. package/src/backend/usage/policy-write.ts +0 -207
  422. package/src/backend/usage/proc-net-dev.test.ts +0 -56
  423. package/src/backend/usage/sampler.test.ts +0 -327
  424. package/src/backend/usage/sampler.ts +0 -282
  425. package/src/backend/usage/store.test.ts +0 -148
  426. package/src/backend/usage/store.ts +0 -177
  427. package/src/backend/usb-enumerator.test.ts +0 -87
  428. package/src/backend/usb-enumerator.ts +0 -181
  429. package/src/backend/usb-mode-transition.test.ts +0 -323
  430. package/src/backend/usb-mode-transition.ts +0 -253
  431. package/src/domain/brand.ts +0 -29
  432. package/src/domain/errors.ts +0 -77
  433. package/src/domain/guards.test.ts +0 -218
  434. package/src/domain/guards.ts +0 -144
  435. package/src/domain/identity.test.ts +0 -83
  436. package/src/domain/identity.ts +0 -165
  437. package/src/domain/index.ts +0 -12
  438. package/src/domain/snapshot.test.ts +0 -266
  439. package/src/domain/snapshot.ts +0 -120
  440. package/src/index.test.ts +0 -6
  441. package/src/index.ts +0 -15
  442. package/src/ports/README.md +0 -61
  443. package/src/ports/forbidden-surface.test.ts +0 -241
  444. package/src/ports/modem-manager.ts +0 -72
  445. package/src/ports/network-manager.ts +0 -87
  446. package/src/ports/ops.ts +0 -60
  447. package/src/ports/ops.type-test.ts +0 -39
  448. package/src/ports/receipts.test.ts +0 -153
  449. package/src/ports/reconcile.test.ts +0 -152
  450. package/src/ports/reconcile.ts +0 -338
  451. package/src/ports/router.ts +0 -29
  452. package/src/redact.test.ts +0 -82
  453. package/src/redact.ts +0 -73
  454. package/src/transport/README.md +0 -65
  455. package/src/transport/calls.ts +0 -113
  456. package/src/transport/characterization.test.ts +0 -260
  457. package/src/transport/codec.test.ts +0 -118
  458. package/src/transport/codec.ts +0 -240
  459. package/src/transport/conformance-python.test.ts +0 -152
  460. package/src/transport/conformance-same-lib.test.ts +0 -115
  461. package/src/transport/dbus-native-lib.d.ts +0 -19
  462. package/src/transport/dbus-native.ts +0 -85
  463. package/src/transport/index.ts +0 -30
  464. package/src/transport/no-library-leak.test.ts +0 -61
  465. package/src/transport/reliability.test.ts +0 -173
  466. package/src/transport/signals.ts +0 -150
  467. package/src/transport/signature.ts +0 -110
  468. package/src/transport/test-support/fake-service.ts +0 -168
  469. package/src/transport/test-support/independent-producer.py +0 -110
  470. package/src/transport/test-support/private-bus.ts +0 -66
  471. package/src/transport/transport.ts +0 -250
  472. package/src/transport/types.ts +0 -118
  473. package/src/usb-mode/catalog-schema.test.ts +0 -181
  474. package/src/usb-mode/catalog-schema.ts +0 -113
  475. package/src/usb-mode/certified-catalog.json +0 -67
  476. package/src/usb-mode/index.ts +0 -58
  477. package/src/usb-mode/ingestion.test.ts +0 -268
  478. package/src/usb-mode/ingestion.ts +0 -297
  479. package/src/usb-mode/promotion-review.ts +0 -117
  480. package/src/usb-mode/usb-devices-parse.ts +0 -196
@@ -0,0 +1,20 @@
1
+ import type { DeviceGeneration, OperationDescriptor, OperationResult } from '../../domain/index.js';
2
+ import type { ProviderExecutionContext } from '../contracts.js';
3
+ import { type HilinkProfile } from './provider.js';
4
+ export type ReadValue = Readonly<Record<string, unknown>>;
5
+ export type ReadOperation = {
6
+ readonly descriptor: OperationDescriptor<never, ReadValue>;
7
+ readonly read: (context: ProviderExecutionContext) => Promise<OperationResult<ReadValue>>;
8
+ };
9
+ export type WriteOperation = {
10
+ readonly descriptor: OperationDescriptor<string | boolean, ReadValue>;
11
+ readonly read: ReadOperation['read'];
12
+ readonly write: (context: ProviderExecutionContext, value: string | boolean) => Promise<OperationResult<ReadValue>>;
13
+ };
14
+ export declare function applied(generation: DeviceGeneration, value: ReadValue): OperationResult<ReadValue>;
15
+ export declare function refused(generation: DeviceGeneration, reason: string): OperationResult<ReadValue>;
16
+ export declare function operationDescriptor<I>(id: string, write: boolean, profile: HilinkProfile): OperationDescriptor<I, ReadValue>;
17
+ export declare function requestSucceeded(status: number, body: string): boolean;
18
+ export declare function capabilityPath(kind: 'status' | 'signal' | 'mode' | 'data'): string;
19
+ export declare function writeDocument(kind: 'mode' | 'data', value: string | boolean): string;
20
+ export declare function readbackMatches(kind: 'mode' | 'data', body: string, value: string | boolean): boolean;
@@ -0,0 +1,56 @@
1
+ import { defineOperationDescriptor } from '../../domain/index.js';
2
+ import { parseHilinkDataCapability, parseHilinkXmlValue } from '../../hardware/router-parsers.js';
3
+ import { HILINK_PATHS } from './provider.js';
4
+ export function applied(generation, value) {
5
+ return { status: 'applied', value, generation, requiresReconciliation: false };
6
+ }
7
+ export function refused(generation, reason) {
8
+ return { status: 'refused', reason, generation, requiresReconciliation: false };
9
+ }
10
+ export function operationDescriptor(id, write, profile) {
11
+ return defineOperationDescriptor({
12
+ id,
13
+ support: {
14
+ read: { supported: true },
15
+ write: write ? { supported: true } : { supported: false, reason: 'read-only' },
16
+ },
17
+ authority: 'provider',
18
+ provider: 'huawei-hilink',
19
+ constraints: { kind: 'unconstrained' },
20
+ livePreconditions: ['fresh-session', 'capability-evidence'],
21
+ availability: { state: 'available' },
22
+ mutationImpact: write ? 'write' : 'read',
23
+ retryClass: 'never',
24
+ readback: write
25
+ ? { required: true, reason: 'fresh-readback', matches: () => true }
26
+ : { required: false },
27
+ rollback: { required: false },
28
+ journal: { required: false },
29
+ admission: { required: true, reason: 'router-session' },
30
+ evidence: { profiles: [profile.id], firmware: [profile.firmware] },
31
+ confidence: 'high',
32
+ });
33
+ }
34
+ export function requestSucceeded(status, body) {
35
+ return status >= 200 && status < 300 && /<response>\s*OK\s*<\/response>/i.test(body);
36
+ }
37
+ export function capabilityPath(kind) {
38
+ return kind === 'status'
39
+ ? HILINK_PATHS.status
40
+ : kind === 'signal'
41
+ ? HILINK_PATHS.signal
42
+ : kind === 'mode'
43
+ ? HILINK_PATHS.modeList
44
+ : HILINK_PATHS.data;
45
+ }
46
+ export function writeDocument(kind, value) {
47
+ return kind === 'mode'
48
+ ? `<?xml version="1.0" encoding="UTF-8"?><request><NetworkMode>${String(value)}</NetworkMode></request>`
49
+ : `<?xml version="1.0" encoding="UTF-8"?><request><dataswitch>${value ? 1 : 0}</dataswitch></request>`;
50
+ }
51
+ export function readbackMatches(kind, body, value) {
52
+ if (kind === 'mode')
53
+ return parseHilinkXmlValue(body, 'NetworkMode') === String(value);
54
+ const parsed = parseHilinkDataCapability(body);
55
+ return parsed.state === 'reported' && parsed.enabled === Boolean(value);
56
+ }
@@ -0,0 +1,52 @@
1
+ import type { NormalizedModemObservation } from '../../observations/index.js';
2
+ import type { ResourceOwnershipPort } from '../../ports/resource-ownership.js';
3
+ import type { ProviderDefinition, ProviderOperationsSurface } from '../contracts.js';
4
+ import { HuaweiProvider, type ReadOperation, type WriteOperation } from './runtime.js';
5
+ import type { HilinkTransport } from './transport.js';
6
+ export declare const HILINK_PATHS: {
7
+ readonly session: '/api/webserver/SesTokInfo';
8
+ readonly loginState: '/api/user/state-login';
9
+ readonly login: '/api/user/login';
10
+ readonly status: '/api/monitoring/status';
11
+ readonly signal: '/api/device/signal';
12
+ readonly modeList: '/api/net/net-mode-list';
13
+ readonly mode: '/api/net/net-mode';
14
+ readonly data: '/api/dialup/mobile-dataswitch';
15
+ };
16
+ export type HilinkProfile = {
17
+ readonly id: string;
18
+ readonly firmware: string;
19
+ readonly passwordType: 3 | 4;
20
+ };
21
+ export declare const HILINK_PROFILES: readonly [{
22
+ readonly id: 'e3372h-22.200-password-type-3';
23
+ readonly firmware: '22.200.05.00.1080';
24
+ readonly passwordType: 3;
25
+ }, {
26
+ readonly id: 'e3372h-22.333-password-type-4';
27
+ readonly firmware: '22.333.01.00.00';
28
+ readonly passwordType: 4;
29
+ }];
30
+ export type HilinkCredentials = {
31
+ readonly username: string;
32
+ readonly password: string;
33
+ };
34
+ export type HilinkOptions = {
35
+ readonly interfaceName: string;
36
+ readonly adminUrl: string;
37
+ readonly transport: HilinkTransport;
38
+ readonly ownership: ResourceOwnershipPort;
39
+ readonly credentials: HilinkCredentials;
40
+ readonly now?: () => number;
41
+ };
42
+ export type HilinkObservation = NormalizedModemObservation;
43
+ export type HuaweiOperations = ProviderOperationsSurface & {
44
+ readonly status: ReadOperation;
45
+ readonly signal: ReadOperation;
46
+ readonly mode: WriteOperation;
47
+ readonly data: WriteOperation;
48
+ };
49
+ export declare function hilinkProfile(profileId: string): HilinkProfile | undefined;
50
+ export declare function createHuaweiHiLinkProvider(options: HilinkOptions): HuaweiProvider;
51
+ export declare function createHuaweiHiLinkDefinition(options: HilinkOptions): ProviderDefinition<HilinkObservation, HuaweiOperations>;
52
+ export { HuaweiProvider as HuaweiHiLinkProvider };
@@ -0,0 +1,76 @@
1
+ import { HuaweiProvider } from './runtime.js';
2
+ export const HILINK_PATHS = {
3
+ session: '/api/webserver/SesTokInfo',
4
+ loginState: '/api/user/state-login',
5
+ login: '/api/user/login',
6
+ status: '/api/monitoring/status',
7
+ signal: '/api/device/signal',
8
+ modeList: '/api/net/net-mode-list',
9
+ mode: '/api/net/net-mode',
10
+ data: '/api/dialup/mobile-dataswitch',
11
+ };
12
+ export const HILINK_PROFILES = [
13
+ {
14
+ id: 'e3372h-22.200-password-type-3',
15
+ firmware: '22.200.05.00.1080',
16
+ passwordType: 3,
17
+ },
18
+ {
19
+ id: 'e3372h-22.333-password-type-4',
20
+ firmware: '22.333.01.00.00',
21
+ passwordType: 4,
22
+ },
23
+ ];
24
+ export function hilinkProfile(profileId) {
25
+ return HILINK_PROFILES.find((profile) => profile.id === profileId);
26
+ }
27
+ export function createHuaweiHiLinkProvider(options) {
28
+ return new HuaweiProvider(options);
29
+ }
30
+ export function createHuaweiHiLinkDefinition(options) {
31
+ const runtime = createHuaweiHiLinkProvider(options);
32
+ return {
33
+ id: 'huawei-hilink',
34
+ profileVersion: '1',
35
+ eligibleTransports: ['network'],
36
+ passiveMatchers: HILINK_PROFILES.map((profile) => ({
37
+ id: `firmware-${profile.firmware}`,
38
+ fact: 'firmware',
39
+ expected: [profile.firmware],
40
+ profiles: [profile.id],
41
+ strength: 'strong',
42
+ required: true,
43
+ })),
44
+ unauthenticatedProbes: [
45
+ {
46
+ id: 'hilink-session-shape',
47
+ run: (request) => runtime.sessionProbe(request),
48
+ },
49
+ ],
50
+ authenticatedProfile: {
51
+ algorithm: 'firmware-selected-hilink-password',
52
+ attemptLimit: 1,
53
+ authenticate: (request, candidates) => runtime.authenticateProfile(request, candidates),
54
+ },
55
+ capabilityReaders: [
56
+ runtime.capability('status'),
57
+ runtime.capability('signal'),
58
+ runtime.capability('mode'),
59
+ runtime.capability('data'),
60
+ ],
61
+ observe: (context) => runtime.observe(context),
62
+ operations: (profile) => runtime.operations(profile),
63
+ contractFixtures: HILINK_PROFILES.map((profile) => ({
64
+ profile: profile.id,
65
+ request: {
66
+ method: 'POST',
67
+ path: HILINK_PATHS.login,
68
+ passwordType: profile.passwordType,
69
+ interfaceBound: true,
70
+ redirects: 'disabled',
71
+ },
72
+ response: { status: 'matched', sessionMaterial: '[redacted]' },
73
+ })),
74
+ };
75
+ }
76
+ export { HuaweiProvider as HuaweiHiLinkProvider };
@@ -0,0 +1,22 @@
1
+ import type { ObservationEnvelope } from '../../domain/index.js';
2
+ import type { AuthenticatedProfileResult, CapabilityReader, ProviderExecutionContext, ProviderMatchRequest } from '../contracts.js';
3
+ import { type HilinkObservation, type HuaweiOperations } from './provider.js';
4
+ import { HilinkSessionRuntime } from './session.js';
5
+ export type { ReadOperation, WriteOperation } from './operations.js';
6
+ export declare class HuaweiProvider extends HilinkSessionRuntime {
7
+ sessionProbe(request: ProviderMatchRequest): Promise<{
8
+ signal: "match" | "unknown";
9
+ strength: 'strong';
10
+ profiles: ("e3372h-22.200-password-type-3" | "e3372h-22.333-password-type-4")[];
11
+ detail: string;
12
+ }>;
13
+ authenticateProfile(request: ProviderMatchRequest, candidates: readonly string[]): Promise<AuthenticatedProfileResult>;
14
+ observe(context: ProviderExecutionContext): Promise<readonly ObservationEnvelope<HilinkObservation>[]>;
15
+ capability(kind: 'status' | 'signal' | 'mode' | 'data'): CapabilityReader;
16
+ operations(profileId: string): HuaweiOperations;
17
+ private sessionFor;
18
+ private capabilitySupported;
19
+ private readOperation;
20
+ private writeOperation;
21
+ private write;
22
+ }
@@ -0,0 +1,171 @@
1
+ import { parseHilinkCapabilities, parseHilinkDataCapability, parseHilinkSession, parseHilinkXmlValue, } from '../../hardware/router-parsers.js';
2
+ import { normalizeHilinkObservation } from '../../observations/sources/hilink.js';
3
+ import { applied, capabilityPath, operationDescriptor, readbackMatches, refused, requestSucceeded, writeDocument, } from './operations.js';
4
+ import { HILINK_PATHS, HILINK_PROFILES, hilinkProfile, } from './provider.js';
5
+ import { HilinkSessionRuntime } from './session.js';
6
+ export class HuaweiProvider extends HilinkSessionRuntime {
7
+ async sessionProbe(request) {
8
+ const profile = HILINK_PROFILES.find((candidate) => candidate.firmware === request.firmware);
9
+ const response = await this.request('GET', HILINK_PATHS.session);
10
+ const matches = response.status === 200 && parseHilinkSession(response.body) !== undefined;
11
+ return {
12
+ signal: matches && profile !== undefined ? 'match' : 'unknown',
13
+ strength: 'strong',
14
+ profiles: profile === undefined ? [] : [profile.id],
15
+ detail: matches ? 'session-token-evidence' : 'session-token-not-proven',
16
+ };
17
+ }
18
+ async authenticateProfile(request, candidates) {
19
+ const candidate = candidates.length === 1 ? hilinkProfile(candidates[0] ?? '') : undefined;
20
+ if (candidate === undefined)
21
+ return { status: 'refused', detail: 'profile-mismatch' };
22
+ const result = await this.authenticate(request, candidate, true);
23
+ if (result.status === 'ready')
24
+ return { status: 'matched', profile: candidate.id, detail: 'login-ok' };
25
+ return {
26
+ status: result.reason === 'unreachable' ? 'unavailable' : 'refused',
27
+ detail: result.reason,
28
+ };
29
+ }
30
+ async observe(context) {
31
+ const ready = await this.sessionFor(context);
32
+ if (ready === undefined)
33
+ return [];
34
+ const [status, signal, modeList, mode] = await Promise.all([
35
+ this.getResponse(HILINK_PATHS.status, ready),
36
+ this.getResponse(HILINK_PATHS.signal, ready),
37
+ this.getResponse(HILINK_PATHS.modeList, ready),
38
+ this.getResponse(HILINK_PATHS.mode, ready),
39
+ ]);
40
+ const input = {
41
+ status: status.body,
42
+ signal: signal.body,
43
+ netModeList: modeList.body,
44
+ netMode: mode.body,
45
+ };
46
+ return [
47
+ normalizeHilinkObservation(input, {
48
+ stableKey: `modem:${this.options.interfaceName}`,
49
+ generation: context.generation,
50
+ sourceEpoch: 1,
51
+ observedAt: (this.options.now?.() ?? Date.now()),
52
+ }),
53
+ ];
54
+ }
55
+ capability(kind) {
56
+ return {
57
+ id: `hilink-${kind}`,
58
+ read: async (context) => {
59
+ const session = await this.sessionFor(context);
60
+ if (session === undefined)
61
+ return { signal: 'unknown', strength: 'strong', detail: 'session-unavailable' };
62
+ const path = capabilityPath(kind);
63
+ const response = await this.getResponse(path, session);
64
+ const supported = this.capabilitySupported(kind, response.body) && !this.authExpired(response);
65
+ return {
66
+ signal: supported ? 'match' : 'mismatch',
67
+ strength: 'strong',
68
+ detail: supported ? 'capability-reported' : 'capability-refused',
69
+ };
70
+ },
71
+ };
72
+ }
73
+ operations(profileId) {
74
+ const profile = hilinkProfile(profileId);
75
+ if (profile === undefined)
76
+ return unsupportedOperations(profileId);
77
+ return {
78
+ access: 'read-write',
79
+ status: this.readOperation('status', HILINK_PATHS.status, profile),
80
+ signal: this.readOperation('signal', HILINK_PATHS.signal, profile),
81
+ mode: this.writeOperation('mode', HILINK_PATHS.mode, profile),
82
+ data: this.writeOperation('data', HILINK_PATHS.data, profile),
83
+ };
84
+ }
85
+ async sessionFor(context) {
86
+ const cached = this.cachedSession(context);
87
+ if (cached !== undefined)
88
+ return cached;
89
+ const profile = hilinkProfile(context.profile);
90
+ if (profile === undefined)
91
+ return undefined;
92
+ const result = await this.authenticate(context, profile, true);
93
+ return result.status === 'ready' ? result.session : undefined;
94
+ }
95
+ capabilitySupported(kind, body) {
96
+ if (kind === 'mode')
97
+ return parseHilinkCapabilities({ netModeList: body }).net_mode.state === 'reported';
98
+ if (kind === 'data')
99
+ return parseHilinkDataCapability(body).state === 'reported';
100
+ return parseHilinkXmlValue(body, 'code') === undefined && /<response>/i.test(body);
101
+ }
102
+ readOperation(id, path, profile) {
103
+ return {
104
+ descriptor: operationDescriptor(id, false, profile),
105
+ read: async (context) => {
106
+ const result = await this.authenticate(context, profile, false);
107
+ if (result.status === 'refused')
108
+ return refused(context.generation, result.reason);
109
+ const response = await this.getResponse(path, result.session);
110
+ if (this.authExpired(response))
111
+ return refused(context.generation, 'auth-expired');
112
+ if (response.status < 200 || response.status >= 300)
113
+ return refused(context.generation, 'http-failure');
114
+ return applied(context.generation, { body: response.body });
115
+ },
116
+ };
117
+ }
118
+ writeOperation(id, path, profile) {
119
+ return {
120
+ descriptor: operationDescriptor(id, true, profile),
121
+ read: this.readOperation(`${id}-read`, path, profile).read,
122
+ write: (context, value) => this.write(context, profile, id, path, value),
123
+ };
124
+ }
125
+ async write(context, profile, kind, path, value) {
126
+ return this.withDevice(context, async () => {
127
+ const ownership = await this.options.ownership.acquire({ resource: 'router-session' });
128
+ if (ownership.status === 'refused')
129
+ return refused(context.generation, 'busy');
130
+ try {
131
+ const ready = await this.authenticate(context, profile, false);
132
+ if (ready.status === 'refused')
133
+ return refused(context.generation, ready.reason);
134
+ const capabilityPath = kind === 'mode' ? HILINK_PATHS.modeList : HILINK_PATHS.data;
135
+ const capability = await this.getResponse(capabilityPath, ready.session);
136
+ if (this.authExpired(capability))
137
+ return refused(context.generation, 'auth-expired');
138
+ if (!this.capabilitySupported(kind, capability.body))
139
+ return refused(context.generation, 'capability-unavailable');
140
+ if (kind === 'mode') {
141
+ const offered = parseHilinkCapabilities({ netModeList: capability.body }).net_mode;
142
+ if (offered.state !== 'reported' ||
143
+ !offered.modes.some((mode) => mode.id === String(value)))
144
+ return refused(context.generation, 'capability-unavailable');
145
+ }
146
+ const body = writeDocument(kind, value);
147
+ const posted = await this.postResponse(path, body, ready.session);
148
+ if (this.authExpired(posted))
149
+ return refused(context.generation, 'auth-expired');
150
+ if (!requestSucceeded(posted.status, posted.body))
151
+ return refused(context.generation, 'http-failure');
152
+ const fresh = await this.authenticate(context, profile, false);
153
+ if (fresh.status === 'refused')
154
+ return refused(context.generation, fresh.reason);
155
+ const readback = await this.getResponse(path, fresh.session);
156
+ if (this.authExpired(readback))
157
+ return refused(context.generation, 'auth-expired');
158
+ const matches = readbackMatches(kind, readback.body, value);
159
+ return matches
160
+ ? applied(context.generation, { body: readback.body })
161
+ : refused(context.generation, 'not-applied');
162
+ }
163
+ finally {
164
+ await ownership.lease.release();
165
+ }
166
+ });
167
+ }
168
+ }
169
+ function unsupportedOperations(_profileId) {
170
+ throw new Error('unsupported-hilink-profile');
171
+ }
@@ -0,0 +1,28 @@
1
+ import type { ProviderExecutionContext, ProviderMatchRequest } from '../contracts.js';
2
+ import { type HilinkOptions, type HilinkProfile } from './provider.js';
3
+ import type { HilinkHttpResponse } from './transport.js';
4
+ export type HilinkSession = {
5
+ readonly cookie: string;
6
+ readonly token: string;
7
+ };
8
+ export type HilinkSessionFailure = 'auth-expired' | 'http-failure' | 'malformed' | 'profile-mismatch' | 'unreachable';
9
+ export type HilinkSessionResult = {
10
+ readonly status: 'ready';
11
+ readonly session: HilinkSession;
12
+ } | {
13
+ readonly status: 'refused';
14
+ readonly reason: HilinkSessionFailure;
15
+ };
16
+ export declare class HilinkSessionRuntime {
17
+ #private;
18
+ protected readonly options: HilinkOptions;
19
+ constructor(options: HilinkOptions);
20
+ protected withDevice<T>(context: ProviderExecutionContext, run: () => Promise<T>): Promise<T>;
21
+ protected sessionKey(context: ProviderMatchRequest): string;
22
+ protected cachedSession(context: ProviderMatchRequest): HilinkSession | undefined;
23
+ protected authenticate(context: ProviderMatchRequest, profile: HilinkProfile, cache: boolean): Promise<HilinkSessionResult>;
24
+ protected authExpired(response: HilinkHttpResponse): boolean;
25
+ protected getResponse(path: string, session: HilinkSession): Promise<HilinkHttpResponse>;
26
+ protected postResponse(path: string, body: string, session: HilinkSession): Promise<HilinkHttpResponse>;
27
+ protected request(method: 'GET' | 'POST', path: string, body?: string, headers?: readonly string[]): Promise<HilinkHttpResponse>;
28
+ }
@@ -0,0 +1,120 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { parseHilinkSession, parseHilinkUserState, parseHilinkXmlValue, } from '../../hardware/router-parsers.js';
3
+ import { HILINK_PATHS } from './provider.js';
4
+ function base64(value) {
5
+ return Buffer.from(value).toString('base64');
6
+ }
7
+ function derivePassword(profile, username, password, token) {
8
+ if (profile.passwordType === 3)
9
+ return base64(password);
10
+ const passwordHash = base64(createHash('sha256').update(password).digest('hex'));
11
+ const loginHash = createHash('sha256').update(`${username}${passwordHash}${token}`).digest('hex');
12
+ return base64(loginHash);
13
+ }
14
+ function escapeXml(value) {
15
+ return value
16
+ .replace(/&/g, '&amp;')
17
+ .replace(/</g, '&lt;')
18
+ .replace(/>/g, '&gt;')
19
+ .replace(/"/g, '&quot;')
20
+ .replace(/'/g, '&apos;');
21
+ }
22
+ function loginDocument(profile, username, password, token) {
23
+ return `<?xml version="1.0" encoding="UTF-8"?><request><Username>${escapeXml(username)}</Username><Password>${derivePassword(profile, username, password, token)}</Password><password_type>${profile.passwordType}</password_type></request>`;
24
+ }
25
+ function responseHeader(response, name) {
26
+ const expected = name.toLowerCase();
27
+ return Object.entries(response.headers ?? {}).find(([key]) => key.toLowerCase() === expected)?.[1];
28
+ }
29
+ function loggedInSession(response, fallback) {
30
+ const cookie = responseHeader(response, 'set-cookie')?.split(';', 1)[0]?.trim() ?? fallback.cookie;
31
+ const tokenHeader = responseHeader(response, '__requestverificationtoken') ??
32
+ responseHeader(response, '__requestverificationtokenone');
33
+ const token = tokenHeader?.split('#', 1)[0]?.trim() ?? fallback.token;
34
+ return { cookie, token };
35
+ }
36
+ export class HilinkSessionRuntime {
37
+ options;
38
+ #authenticated = new Map();
39
+ #serial = new Map();
40
+ constructor(options) {
41
+ this.options = options;
42
+ }
43
+ async withDevice(context, run) {
44
+ const key = String(context.physicalModemId);
45
+ const prior = this.#serial.get(key) ?? Promise.resolve();
46
+ let release = () => { };
47
+ const current = new Promise((resolve) => {
48
+ release = resolve;
49
+ });
50
+ const chain = prior.then(() => current);
51
+ this.#serial.set(key, chain);
52
+ await prior;
53
+ try {
54
+ return await run();
55
+ }
56
+ finally {
57
+ release();
58
+ if (this.#serial.get(key) === chain)
59
+ this.#serial.delete(key);
60
+ }
61
+ }
62
+ sessionKey(context) {
63
+ return `${context.physicalModemId}:${context.generation}`;
64
+ }
65
+ cachedSession(context) {
66
+ return this.#authenticated.get(this.sessionKey(context));
67
+ }
68
+ async authenticate(context, profile, cache) {
69
+ const sessionResponse = await this.request('GET', HILINK_PATHS.session);
70
+ if (sessionResponse.status === 401 || sessionResponse.status === 403)
71
+ return { status: 'refused', reason: 'auth-expired' };
72
+ if (sessionResponse.status !== 200)
73
+ return { status: 'refused', reason: 'unreachable' };
74
+ const initial = parseHilinkSession(sessionResponse.body);
75
+ if (initial === undefined)
76
+ return { status: 'refused', reason: 'malformed' };
77
+ const stateResponse = await this.getResponse(HILINK_PATHS.loginState, initial);
78
+ if (this.authExpired(stateResponse))
79
+ return { status: 'refused', reason: 'auth-expired' };
80
+ const state = parseHilinkUserState(stateResponse.body);
81
+ if (state === undefined)
82
+ return { status: 'refused', reason: 'malformed' };
83
+ if (state.passwordType !== profile.passwordType)
84
+ return { status: 'refused', reason: 'profile-mismatch' };
85
+ const login = await this.postResponse(HILINK_PATHS.login, loginDocument(profile, this.options.credentials.username, this.options.credentials.password, initial.token), initial);
86
+ if (this.authExpired(login))
87
+ return { status: 'refused', reason: 'auth-expired' };
88
+ if (login.status !== 200 || !/<response>\s*OK\s*<\/response>/i.test(login.body))
89
+ return { status: 'refused', reason: 'http-failure' };
90
+ const session = loggedInSession(login, initial);
91
+ if (cache)
92
+ this.#authenticated.set(this.sessionKey(context), session);
93
+ return { status: 'ready', session };
94
+ }
95
+ authExpired(response) {
96
+ return (response.status === 401 ||
97
+ response.status === 403 ||
98
+ parseHilinkXmlValue(response.body, 'code') === '125002');
99
+ }
100
+ getResponse(path, session) {
101
+ return this.request('GET', path, undefined, [`Cookie: ${session.cookie}`]);
102
+ }
103
+ postResponse(path, body, session) {
104
+ return this.request('POST', path, body, [
105
+ `Cookie: ${session.cookie}`,
106
+ `__RequestVerificationToken: ${session.token}`,
107
+ 'Content-Type: application/xml',
108
+ ]);
109
+ }
110
+ request(method, path, body, headers = []) {
111
+ return this.options.transport.request({
112
+ method,
113
+ url: `${this.options.adminUrl}${path}`,
114
+ ...(body === undefined ? {} : { body }),
115
+ headers,
116
+ interfaceName: this.options.interfaceName,
117
+ redirect: 'error',
118
+ });
119
+ }
120
+ }
@@ -0,0 +1,19 @@
1
+ export type HilinkHttpRequest = {
2
+ readonly method: 'GET' | 'POST';
3
+ readonly url: string;
4
+ readonly body?: string;
5
+ readonly headers: readonly string[];
6
+ readonly interfaceName: string;
7
+ readonly redirect: 'error';
8
+ };
9
+ export type HilinkHttpResponse = {
10
+ readonly status: number;
11
+ readonly body: string;
12
+ readonly headers?: Readonly<Record<string, string>>;
13
+ };
14
+ export interface HilinkTransport {
15
+ request(request: HilinkHttpRequest): Promise<HilinkHttpResponse>;
16
+ }
17
+ export type HilinkReplayExchange = HilinkHttpRequest & {
18
+ readonly response: HilinkHttpResponse;
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export * from './contracts.js';
2
+ export * from './huawei-hilink/index.js';
3
+ export * from './matcher.js';
4
+ export * from './modem-manager/index.js';
5
+ export * from './network-manager/index.js';
6
+ export * from './registry.js';
7
+ export * from './ufi-himi/index.js';
8
+ export * from './zte-goform/index.js';
@@ -0,0 +1,8 @@
1
+ export * from './contracts.js';
2
+ export * from './huawei-hilink/index.js';
3
+ export * from './matcher.js';
4
+ export * from './modem-manager/index.js';
5
+ export * from './network-manager/index.js';
6
+ export * from './registry.js';
7
+ export * from './ufi-himi/index.js';
8
+ export * from './zte-goform/index.js';
@@ -0,0 +1,3 @@
1
+ import type { ProviderMatcher } from './contracts.js';
2
+ import type { ProviderRegistry } from './registry.js';
3
+ export declare function createProviderMatcher(registry: ProviderRegistry): ProviderMatcher;