@ceralive/modem-control 0.2.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +317 -0
- package/dist/backend/at-lease.d.ts +57 -0
- package/dist/backend/at-lease.js +109 -0
- package/dist/backend/cell-info.d.ts +46 -0
- package/dist/backend/cell-info.js +124 -0
- package/dist/backend/constants.d.ts +24 -0
- package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
- package/dist/backend/device-classifier.d.ts +46 -0
- package/dist/backend/device-classifier.js +258 -0
- package/dist/backend/enrichment.d.ts +28 -0
- package/dist/backend/enrichment.js +59 -0
- package/dist/backend/features.d.ts +61 -0
- package/dist/backend/features.js +109 -0
- package/dist/backend/identity-ladder.d.ts +57 -0
- package/dist/backend/identity-ladder.js +158 -0
- package/dist/backend/identity-registry.d.ts +51 -0
- package/dist/backend/identity-registry.js +101 -0
- package/dist/backend/index.d.ts +30 -0
- package/dist/backend/index.js +35 -0
- package/dist/backend/lifecycle-interlock.d.ts +25 -0
- package/dist/backend/lifecycle-interlock.js +18 -0
- package/dist/backend/managed-objects.d.ts +39 -0
- package/dist/backend/managed-objects.js +82 -0
- package/dist/backend/mapping.d.ts +11 -0
- package/dist/backend/mapping.js +148 -0
- package/dist/backend/mm-backend.d.ts +44 -0
- package/dist/backend/mm-backend.js +154 -0
- package/dist/backend/mm-location.d.ts +21 -0
- package/dist/backend/mm-location.js +237 -0
- package/dist/backend/mm-mutations.d.ts +42 -0
- package/dist/backend/mm-mutations.js +259 -0
- package/dist/backend/modem-actor.d.ts +41 -0
- package/dist/backend/modem-actor.js +78 -0
- package/dist/backend/nm-auto-apn.d.ts +54 -0
- package/dist/backend/nm-auto-apn.js +124 -0
- package/dist/backend/nm-gsm-fields.d.ts +23 -0
- package/dist/backend/nm-gsm-fields.js +107 -0
- package/dist/backend/nmcli-nm-port.d.ts +28 -0
- package/dist/backend/nmcli-nm-port.js +173 -0
- package/dist/backend/nmcli-runner.d.ts +24 -0
- package/dist/backend/nmcli-runner.js +35 -0
- package/dist/backend/observer.d.ts +37 -0
- package/dist/backend/observer.js +219 -0
- package/dist/backend/power-contract.d.ts +49 -0
- package/dist/backend/power-contract.js +34 -0
- package/dist/backend/recovery-attribution.d.ts +32 -0
- package/dist/backend/recovery-attribution.js +57 -0
- package/dist/backend/recovery-budget.d.ts +45 -0
- package/dist/backend/recovery-budget.js +44 -0
- package/dist/backend/recovery-ladder.d.ts +94 -0
- package/dist/backend/recovery-ladder.js +116 -0
- package/dist/backend/router-ethernet.d.ts +19 -0
- package/dist/backend/router-ethernet.js +66 -0
- package/dist/backend/row-store.d.ts +13 -0
- package/dist/backend/row-store.js +82 -0
- package/dist/backend/signal-setup.d.ts +30 -0
- package/dist/backend/signal-setup.js +92 -0
- package/dist/backend/sim-unlock.d.ts +13 -0
- package/dist/backend/sim-unlock.js +153 -0
- package/dist/backend/transition-preconditions.d.ts +76 -0
- package/dist/backend/transition-preconditions.js +64 -0
- package/dist/backend/usage/accounting.d.ts +39 -0
- package/dist/backend/usage/accounting.js +73 -0
- package/dist/backend/usage/billing-cycle.d.ts +11 -0
- package/dist/backend/usage/billing-cycle.js +39 -0
- package/dist/backend/usage/boot-id.d.ts +6 -0
- package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
- package/dist/backend/usage/index.d.ts +8 -0
- package/dist/backend/usage/index.js +11 -0
- package/dist/backend/usage/policy-store.d.ts +50 -0
- package/dist/backend/usage/policy-store.js +161 -0
- package/dist/backend/usage/policy-write.d.ts +65 -0
- package/dist/backend/usage/policy-write.js +112 -0
- package/dist/backend/usage/proc-net-dev.d.ts +18 -0
- package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
- package/dist/backend/usage/sampler.d.ts +75 -0
- package/dist/backend/usage/sampler.js +211 -0
- package/dist/backend/usage/store.d.ts +38 -0
- package/dist/backend/usage/store.js +126 -0
- package/dist/backend/usb-device-snapshot.d.ts +31 -0
- package/dist/backend/usb-device-snapshot.js +1 -0
- package/dist/backend/usb-enumerator.d.ts +21 -0
- package/dist/backend/usb-enumerator.js +153 -0
- package/dist/backend/usb-mode-transition.d.ts +29 -0
- package/dist/backend/usb-mode-transition.js +196 -0
- package/dist/band/band-names.d.ts +42 -0
- package/dist/band/band-names.js +150 -0
- package/dist/band/certification.d.ts +84 -0
- package/dist/band/certification.js +127 -0
- package/dist/band/certified-bands.json +4 -0
- package/dist/band/index.d.ts +2 -0
- package/dist/band/index.js +8 -0
- package/dist/capability/detect.d.ts +52 -0
- package/dist/capability/detect.js +86 -0
- package/dist/capability/five-g-preference.d.ts +104 -0
- package/dist/capability/five-g-preference.js +171 -0
- package/dist/capability/index.d.ts +3 -0
- package/dist/capability/index.js +10 -0
- package/dist/capability/support-claim.d.ts +39 -0
- package/dist/capability/support-claim.js +81 -0
- package/dist/domain/brand.d.ts +10 -0
- package/dist/domain/brand.js +21 -0
- package/dist/domain/errors.d.ts +32 -0
- package/dist/domain/errors.js +48 -0
- package/dist/domain/generation.d.ts +8 -0
- package/dist/domain/generation.js +12 -0
- package/dist/domain/guards.d.ts +6 -0
- package/dist/domain/guards.js +127 -0
- package/dist/domain/identity.d.ts +109 -0
- package/dist/domain/identity.js +86 -0
- package/dist/domain/index.d.ts +14 -0
- package/dist/domain/index.js +18 -0
- package/dist/domain/mm-enums.d.ts +12 -0
- package/dist/domain/mm-enums.js +139 -0
- package/dist/domain/modem-presentation.d.ts +10 -0
- package/dist/domain/modem-presentation.js +39 -0
- package/dist/domain/observation.d.ts +39 -0
- package/dist/domain/observation.js +4 -0
- package/dist/domain/operation.d.ts +118 -0
- package/dist/domain/operation.js +85 -0
- package/dist/domain/physical-identity.d.ts +43 -0
- package/dist/domain/physical-identity.js +113 -0
- package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
- package/dist/domain/policy.js +38 -0
- package/dist/domain/shadow-divergence.d.ts +27 -0
- package/dist/domain/shadow-divergence.js +70 -0
- package/dist/domain/snapshot.d.ts +53 -0
- package/dist/domain/snapshot.js +75 -0
- package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
- package/dist/domain/state.js +38 -0
- package/dist/fcc/coverage.d.ts +63 -0
- package/dist/fcc/coverage.js +102 -0
- package/dist/fcc/index.d.ts +3 -0
- package/dist/fcc/index.js +12 -0
- package/dist/fcc/policy-store.d.ts +40 -0
- package/dist/fcc/policy-store.js +146 -0
- package/dist/fcc/policy-write.d.ts +32 -0
- package/dist/fcc/policy-write.js +37 -0
- package/dist/hardware/hilink-protocol.d.ts +39 -0
- package/dist/hardware/hilink-protocol.js +58 -0
- package/dist/hardware/index.d.ts +3 -0
- package/dist/hardware/index.js +15 -0
- package/dist/hardware/router-parsers.d.ts +89 -0
- package/dist/hardware/router-parsers.js +234 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +26 -0
- package/dist/journal/codec.d.ts +44 -0
- package/dist/journal/codec.js +198 -0
- package/dist/journal/engine.d.ts +28 -0
- package/dist/journal/engine.js +68 -0
- package/dist/journal/entry.d.ts +74 -0
- package/dist/journal/entry.js +56 -0
- package/dist/journal/index.d.ts +6 -0
- package/dist/journal/index.js +6 -0
- package/dist/journal/legacy-ceraui.d.ts +73 -0
- package/dist/journal/legacy-ceraui.js +227 -0
- package/dist/journal/recovery.d.ts +58 -0
- package/dist/journal/recovery.js +117 -0
- package/dist/journal/store.d.ts +55 -0
- package/dist/journal/store.js +150 -0
- package/dist/location/fix-state.d.ts +53 -0
- package/dist/location/fix-state.js +75 -0
- package/dist/location/index.d.ts +2 -0
- package/dist/location/index.js +8 -0
- package/dist/location/nmea.d.ts +10 -0
- package/dist/location/nmea.js +89 -0
- package/dist/observations/envelope.d.ts +63 -0
- package/dist/observations/envelope.js +77 -0
- package/dist/observations/freshness.d.ts +28 -0
- package/dist/observations/freshness.js +76 -0
- package/dist/observations/index.d.ts +13 -0
- package/dist/observations/index.js +24 -0
- package/dist/observations/metric.d.ts +47 -0
- package/dist/observations/metric.js +73 -0
- package/dist/observations/model.d.ts +80 -0
- package/dist/observations/model.js +11 -0
- package/dist/observations/provenance.d.ts +94 -0
- package/dist/observations/provenance.js +67 -0
- package/dist/observations/raw.d.ts +42 -0
- package/dist/observations/raw.js +146 -0
- package/dist/observations/reading.d.ts +51 -0
- package/dist/observations/reading.js +65 -0
- package/dist/observations/sources/hilink.d.ts +10 -0
- package/dist/observations/sources/hilink.js +84 -0
- package/dist/observations/sources/modemmanager.d.ts +18 -0
- package/dist/observations/sources/modemmanager.js +239 -0
- package/dist/observations/sources/router-shared.d.ts +29 -0
- package/dist/observations/sources/router-shared.js +68 -0
- package/dist/observations/sources/ufi.d.ts +10 -0
- package/dist/observations/sources/ufi.js +111 -0
- package/dist/observations/sources/zte.d.ts +7 -0
- package/dist/observations/sources/zte.js +71 -0
- package/dist/observations/state-separation.d.ts +64 -0
- package/dist/observations/state-separation.js +52 -0
- package/dist/operations/contracts.d.ts +72 -0
- package/dist/operations/contracts.js +1 -0
- package/dist/operations/index.d.ts +1 -0
- package/dist/operations/index.js +1 -0
- package/dist/operations/operation-engine.d.ts +16 -0
- package/dist/operations/operation-engine.js +194 -0
- package/dist/ports/index.d.ts +12 -0
- package/{src/ports/index.ts → dist/ports/index.js} +12 -8
- package/dist/ports/location.d.ts +87 -0
- package/dist/ports/location.js +36 -0
- package/dist/ports/modem-manager.d.ts +89 -0
- package/dist/ports/modem-manager.js +9 -0
- package/dist/ports/mutation-admission.d.ts +27 -0
- package/dist/ports/mutation-admission.js +9 -0
- package/dist/ports/network-manager.d.ts +68 -0
- package/dist/ports/network-manager.js +13 -0
- package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
- package/dist/ports/observation.js +7 -0
- package/dist/ports/ops.d.ts +44 -0
- package/dist/ports/ops.js +16 -0
- package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
- package/dist/ports/receipts.js +9 -0
- package/dist/ports/reconcile.d.ts +33 -0
- package/dist/ports/reconcile.js +200 -0
- package/dist/ports/resource-ownership.d.ts +29 -0
- package/dist/ports/resource-ownership.js +1 -0
- package/dist/ports/router.d.ts +19 -0
- package/dist/ports/router.js +7 -0
- package/dist/ports/sms.d.ts +64 -0
- package/dist/ports/sms.js +24 -0
- package/dist/ports/uhubctl.d.ts +6 -0
- package/dist/ports/uhubctl.js +1 -0
- package/dist/providers/contracts.d.ts +124 -0
- package/dist/providers/contracts.js +10 -0
- package/dist/providers/huawei-hilink/index.d.ts +2 -0
- package/dist/providers/huawei-hilink/index.js +2 -0
- package/dist/providers/huawei-hilink/operations.d.ts +20 -0
- package/dist/providers/huawei-hilink/operations.js +56 -0
- package/dist/providers/huawei-hilink/provider.d.ts +52 -0
- package/dist/providers/huawei-hilink/provider.js +76 -0
- package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
- package/dist/providers/huawei-hilink/runtime.js +171 -0
- package/dist/providers/huawei-hilink/session.d.ts +28 -0
- package/dist/providers/huawei-hilink/session.js +120 -0
- package/dist/providers/huawei-hilink/transport.d.ts +19 -0
- package/dist/providers/huawei-hilink/transport.js +1 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/matcher.d.ts +3 -0
- package/dist/providers/matcher.js +205 -0
- package/dist/providers/modem-manager/errors.d.ts +7 -0
- package/dist/providers/modem-manager/errors.js +37 -0
- package/dist/providers/modem-manager/generic-operations.d.ts +8 -0
- package/dist/providers/modem-manager/generic-operations.js +207 -0
- package/dist/providers/modem-manager/index.d.ts +3 -0
- package/dist/providers/modem-manager/index.js +3 -0
- package/dist/providers/modem-manager/module-operations.d.ts +21 -0
- package/dist/providers/modem-manager/module-operations.js +118 -0
- package/dist/providers/modem-manager/provider.d.ts +39 -0
- package/dist/providers/modem-manager/provider.js +152 -0
- package/dist/providers/modem-manager/snapshot.d.ts +5 -0
- package/dist/providers/modem-manager/snapshot.js +204 -0
- package/dist/providers/modem-manager/types.d.ts +135 -0
- package/dist/providers/modem-manager/types.js +1 -0
- package/dist/providers/network-manager/adapter.d.ts +71 -0
- package/dist/providers/network-manager/adapter.js +348 -0
- package/dist/providers/network-manager/index.d.ts +2 -0
- package/dist/providers/network-manager/index.js +2 -0
- package/dist/providers/network-manager/types.d.ts +163 -0
- package/dist/providers/network-manager/types.js +77 -0
- package/dist/providers/registry.d.ts +13 -0
- package/dist/providers/registry.js +33 -0
- package/dist/providers/ufi-himi/index.d.ts +6 -0
- package/dist/providers/ufi-himi/index.js +6 -0
- package/dist/providers/ufi-himi/operations.d.ts +41 -0
- package/dist/providers/ufi-himi/operations.js +66 -0
- package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
- package/dist/providers/ufi-himi/prohibitions.js +88 -0
- package/dist/providers/ufi-himi/provider.d.ts +41 -0
- package/dist/providers/ufi-himi/provider.js +204 -0
- package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
- package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
- package/dist/providers/ufi-himi/session.d.ts +46 -0
- package/dist/providers/ufi-himi/session.js +92 -0
- package/dist/providers/ufi-himi/transport.d.ts +29 -0
- package/dist/providers/ufi-himi/transport.js +25 -0
- package/dist/providers/zte-goform/index.d.ts +2 -0
- package/dist/providers/zte-goform/index.js +2 -0
- package/dist/providers/zte-goform/provider.d.ts +51 -0
- package/dist/providers/zte-goform/provider.js +101 -0
- package/dist/providers/zte-goform/session.d.ts +17 -0
- package/dist/providers/zte-goform/session.js +133 -0
- package/dist/providers/zte-goform/transport.d.ts +16 -0
- package/dist/providers/zte-goform/transport.js +1 -0
- package/dist/radio/band-truth.d.ts +50 -0
- package/dist/radio/band-truth.js +92 -0
- package/dist/radio/index.d.ts +3 -0
- package/dist/radio/index.js +10 -0
- package/dist/radio/mode-combinations.d.ts +78 -0
- package/dist/radio/mode-combinations.js +198 -0
- package/dist/radio/mode-truth.d.ts +67 -0
- package/dist/radio/mode-truth.js +112 -0
- package/dist/redact.d.ts +15 -0
- package/dist/redact.js +189 -0
- package/dist/safety/composition-root.d.ts +28 -0
- package/dist/safety/composition-root.js +65 -0
- package/dist/safety/flock-resource-ownership.d.ts +11 -0
- package/dist/safety/flock-resource-ownership.js +151 -0
- package/dist/safety/index.d.ts +2 -0
- package/dist/safety/index.js +2 -0
- package/dist/sms/dbus-messaging.d.ts +17 -0
- package/dist/sms/dbus-messaging.js +185 -0
- package/dist/sms/inbox-store.d.ts +10 -0
- package/dist/sms/inbox-store.js +82 -0
- package/dist/sms/index.d.ts +4 -0
- package/dist/sms/index.js +10 -0
- package/dist/sms/mmcli-parse.d.ts +54 -0
- package/dist/sms/mmcli-parse.js +224 -0
- package/dist/sms/normalize.d.ts +42 -0
- package/dist/sms/normalize.js +95 -0
- package/dist/testing/domain-fakes.d.ts +58 -0
- package/dist/testing/domain-fakes.js +98 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +17 -0
- package/dist/testing/provider-fakes.d.ts +45 -0
- package/dist/testing/provider-fakes.js +64 -0
- package/dist/transport/calls.d.ts +9 -0
- package/dist/transport/calls.js +88 -0
- package/dist/transport/codec.d.ts +3 -0
- package/dist/transport/codec.js +207 -0
- package/dist/transport/dbus-native.d.ts +57 -0
- package/dist/transport/dbus-native.js +17 -0
- package/dist/transport/errors.d.ts +21 -0
- package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
- package/dist/transport/index.d.ts +4 -0
- package/dist/transport/index.js +9 -0
- package/dist/transport/signals.d.ts +15 -0
- package/dist/transport/signals.js +123 -0
- package/dist/transport/signature.d.ts +7 -0
- package/dist/transport/signature.js +94 -0
- package/dist/transport/transport.d.ts +2 -0
- package/dist/transport/transport.js +202 -0
- package/dist/transport/types.d.ts +61 -0
- package/dist/transport/types.js +19 -0
- package/dist/usb-mode/catalog-schema.d.ts +139 -0
- package/dist/usb-mode/catalog-schema.js +97 -0
- package/dist/usb-mode/catalog.d.ts +21 -0
- package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
- package/dist/usb-mode/certified-catalog.json +67 -0
- package/dist/usb-mode/index.d.ts +5 -0
- package/dist/usb-mode/index.js +15 -0
- package/dist/usb-mode/ingestion.d.ts +111 -0
- package/dist/usb-mode/ingestion.js +187 -0
- package/dist/usb-mode/promotion-review.d.ts +21 -0
- package/dist/usb-mode/promotion-review.js +87 -0
- package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
- package/dist/usb-mode/usb-devices-parse.js +157 -0
- package/dist/ussd/calls.d.ts +32 -0
- package/dist/ussd/calls.js +96 -0
- package/dist/ussd/index.d.ts +5 -0
- package/dist/ussd/index.js +12 -0
- package/dist/ussd/mm-ussd.d.ts +37 -0
- package/dist/ussd/mm-ussd.js +205 -0
- package/dist/ussd/refusal.d.ts +53 -0
- package/dist/ussd/refusal.js +154 -0
- package/dist/ussd/registration.d.ts +20 -0
- package/dist/ussd/registration.js +101 -0
- package/dist/ussd/session.d.ts +84 -0
- package/dist/ussd/session.js +163 -0
- package/package.json +38 -4
- package/src/backend/at-lease.test.ts +0 -106
- package/src/backend/at-lease.ts +0 -158
- package/src/backend/cell-info.test.ts +0 -154
- package/src/backend/cell-info.ts +0 -160
- package/src/backend/device-classifier.test.ts +0 -168
- package/src/backend/device-classifier.ts +0 -248
- package/src/backend/enrichment.ts +0 -96
- package/src/backend/features.test.ts +0 -162
- package/src/backend/features.ts +0 -179
- package/src/backend/identity-ladder.test.ts +0 -117
- package/src/backend/identity-ladder.ts +0 -221
- package/src/backend/identity-registry.test.ts +0 -89
- package/src/backend/identity-registry.ts +0 -151
- package/src/backend/index.ts +0 -221
- package/src/backend/lifecycle-interlock.ts +0 -38
- package/src/backend/managed-objects.ts +0 -108
- package/src/backend/mapping.ts +0 -160
- package/src/backend/mm-backend.ts +0 -191
- package/src/backend/mm-mutations.ts +0 -228
- package/src/backend/modem-actor.test.ts +0 -95
- package/src/backend/modem-actor.ts +0 -112
- package/src/backend/nm-auto-apn.ts +0 -161
- package/src/backend/nm-gsm-fields.ts +0 -122
- package/src/backend/nmcli-nm-port.ts +0 -228
- package/src/backend/nmcli-runner.ts +0 -52
- package/src/backend/observer.ts +0 -297
- package/src/backend/power-contract.test.ts +0 -40
- package/src/backend/power-contract.ts +0 -83
- package/src/backend/recovery-attribution.test.ts +0 -102
- package/src/backend/recovery-attribution.ts +0 -86
- package/src/backend/recovery-budget.test.ts +0 -64
- package/src/backend/recovery-budget.ts +0 -84
- package/src/backend/recovery-ladder.test.ts +0 -257
- package/src/backend/recovery-ladder.ts +0 -249
- package/src/backend/router-ethernet.test.ts +0 -71
- package/src/backend/router-ethernet.ts +0 -90
- package/src/backend/row-store.ts +0 -105
- package/src/backend/signal-setup.ts +0 -112
- package/src/backend/sim-unlock.ts +0 -193
- package/src/backend/transition-preconditions.ts +0 -149
- package/src/backend/usage/accounting.test.ts +0 -147
- package/src/backend/usage/accounting.ts +0 -123
- package/src/backend/usage/billing-cycle.test.ts +0 -62
- package/src/backend/usage/billing-cycle.ts +0 -45
- package/src/backend/usage/index.ts +0 -37
- package/src/backend/usage/proc-net-dev.test.ts +0 -56
- package/src/backend/usage/sampler.test.ts +0 -219
- package/src/backend/usage/sampler.ts +0 -228
- package/src/backend/usage/store.test.ts +0 -148
- package/src/backend/usage/store.ts +0 -177
- package/src/backend/usb-enumerator.test.ts +0 -87
- package/src/backend/usb-enumerator.ts +0 -181
- package/src/backend/usb-mode-transition.test.ts +0 -323
- package/src/backend/usb-mode-transition.ts +0 -253
- package/src/domain/brand.ts +0 -29
- package/src/domain/errors.ts +0 -77
- package/src/domain/guards.test.ts +0 -218
- package/src/domain/guards.ts +0 -144
- package/src/domain/identity.test.ts +0 -83
- package/src/domain/identity.ts +0 -165
- package/src/domain/index.ts +0 -12
- package/src/domain/snapshot.test.ts +0 -266
- package/src/domain/snapshot.ts +0 -120
- package/src/index.test.ts +0 -6
- package/src/index.ts +0 -15
- package/src/ports/README.md +0 -61
- package/src/ports/forbidden-surface.test.ts +0 -241
- package/src/ports/modem-manager.ts +0 -72
- package/src/ports/network-manager.ts +0 -87
- package/src/ports/ops.ts +0 -60
- package/src/ports/ops.type-test.ts +0 -39
- package/src/ports/receipts.test.ts +0 -153
- package/src/ports/reconcile.test.ts +0 -152
- package/src/ports/reconcile.ts +0 -338
- package/src/ports/router.ts +0 -29
- package/src/redact.test.ts +0 -82
- package/src/redact.ts +0 -73
- package/src/transport/README.md +0 -65
- package/src/transport/calls.ts +0 -113
- package/src/transport/characterization.test.ts +0 -260
- package/src/transport/codec.test.ts +0 -118
- package/src/transport/codec.ts +0 -240
- package/src/transport/conformance-python.test.ts +0 -152
- package/src/transport/conformance-same-lib.test.ts +0 -115
- package/src/transport/dbus-native-lib.d.ts +0 -19
- package/src/transport/dbus-native.ts +0 -85
- package/src/transport/index.ts +0 -30
- package/src/transport/no-library-leak.test.ts +0 -61
- package/src/transport/reliability.test.ts +0 -173
- package/src/transport/signals.ts +0 -150
- package/src/transport/signature.ts +0 -110
- package/src/transport/test-support/fake-service.ts +0 -168
- package/src/transport/test-support/independent-producer.py +0 -110
- package/src/transport/test-support/private-bus.ts +0 -66
- package/src/transport/transport.ts +0 -250
- package/src/transport/types.ts +0 -118
- package/src/usb-mode/catalog-schema.test.ts +0 -181
- package/src/usb-mode/catalog-schema.ts +0 -113
- package/src/usb-mode/certified-catalog.json +0 -67
- package/src/usb-mode/index.ts +0 -27
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// The SMS port — LIST / READ and Added/Deleted observation. NOTHING ELSE.
|
|
2
|
+
//
|
|
3
|
+
// READ-ONLY IS PERMANENT, NOT A PHASE LIMITATION. There is no verb here that
|
|
4
|
+
// composes, stores, sends, or deletes a message, and none may ever be added.
|
|
5
|
+
// Sending or deleting an SMS is billable and irreversible, and it turns a
|
|
6
|
+
// diagnostic read into real modem-control capability over the subscriber's
|
|
7
|
+
// account. CeraUI carries the same contract on its own side, enforced by a grep
|
|
8
|
+
// gate (`tests/modem-sms-readonly-gate.test.ts`); `sms/readonly-gate.test.ts`
|
|
9
|
+
// is this package's half. Neither may be weakened to land a write path — that
|
|
10
|
+
// is a new spec change with its own confirmation/interlock design.
|
|
11
|
+
//
|
|
12
|
+
// THE OBSERVATION MODEL IS "LIST ONCE, THEN FOLLOW THE SIGNALS". ModemManager's
|
|
13
|
+
// Messaging interface emits `Added` and `Deleted` for every inbox change, so a
|
|
14
|
+
// consumer lists once at start and folds events from then on. Re-listing on a
|
|
15
|
+
// poll tick is the anti-pattern this port exists to remove: it costs one method
|
|
16
|
+
// call per message per tick and still cannot report an arrival any sooner than
|
|
17
|
+
// the tick it lands on.
|
|
18
|
+
//
|
|
19
|
+
// CONTENT NEVER RIDES A DIAGNOSTIC. A message body routinely carries a one-time
|
|
20
|
+
// code and its originator identifies the subscriber, so nothing on this port
|
|
21
|
+
// puts either into a reason string, a receipt, or a log line — see
|
|
22
|
+
// `../redact.ts` for the key class and `../sms/mmcli-parse.ts` for the
|
|
23
|
+
// content-free parse errors.
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PowerCapability, PowerCycleContext, PowerCycleResult } from '../backend/power-contract.js';
|
|
2
|
+
/** Consumer-supplied USB-hub actuator. This package intentionally ships no implementation. */
|
|
3
|
+
export interface UhubctlPort {
|
|
4
|
+
readonly capability: PowerCapability;
|
|
5
|
+
cycle(context: PowerCycleContext): Promise<PowerCycleResult>;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { DeviceGeneration, ObservationEnvelope, OperationDescriptor, OperationResult, PhysicalModemId } from '../domain/index.js';
|
|
2
|
+
export declare const PROVIDER_TRANSPORTS: readonly ["usb", "pci", "network", "modemmanager"];
|
|
3
|
+
export type ProviderTransport = (typeof PROVIDER_TRANSPORTS)[number];
|
|
4
|
+
export declare const PASSIVE_FACT_KINDS: readonly ["usb", "pci", "interface", "driver", "gateway", "model", "firmware"];
|
|
5
|
+
export type PassiveFactKind = (typeof PASSIVE_FACT_KINDS)[number];
|
|
6
|
+
export type EvidenceStrength = 'none' | 'weak' | 'moderate' | 'strong';
|
|
7
|
+
export type MatcherScore = 'unsupported' | 'maybe' | 'likely' | 'supported';
|
|
8
|
+
export type PassiveFact = {
|
|
9
|
+
readonly kind: PassiveFactKind;
|
|
10
|
+
readonly value: string;
|
|
11
|
+
};
|
|
12
|
+
export type ProviderMatchRequest = {
|
|
13
|
+
readonly physicalModemId: PhysicalModemId;
|
|
14
|
+
readonly generation: DeviceGeneration;
|
|
15
|
+
readonly transport: ProviderTransport;
|
|
16
|
+
readonly passiveFacts: readonly PassiveFact[];
|
|
17
|
+
readonly composition: string;
|
|
18
|
+
readonly firmware?: string;
|
|
19
|
+
};
|
|
20
|
+
export type ProviderExecutionContext = ProviderMatchRequest & {
|
|
21
|
+
readonly profile: string;
|
|
22
|
+
};
|
|
23
|
+
export type PassiveMatcher = {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly fact: PassiveFactKind;
|
|
26
|
+
readonly expected: readonly string[];
|
|
27
|
+
readonly profiles: readonly string[];
|
|
28
|
+
readonly strength: Exclude<EvidenceStrength, 'none'>;
|
|
29
|
+
readonly required: boolean;
|
|
30
|
+
};
|
|
31
|
+
export type FingerprintResult = {
|
|
32
|
+
readonly signal: 'match' | 'mismatch' | 'unknown';
|
|
33
|
+
readonly strength: Exclude<EvidenceStrength, 'none'>;
|
|
34
|
+
readonly profiles: readonly string[];
|
|
35
|
+
readonly detail: string;
|
|
36
|
+
};
|
|
37
|
+
export type UnauthenticatedProbe = {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly run: (context: ProviderMatchRequest) => Promise<FingerprintResult>;
|
|
40
|
+
};
|
|
41
|
+
export type CapabilityReader = {
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly read: (context: ProviderExecutionContext) => Promise<Omit<FingerprintResult, 'profiles'>>;
|
|
44
|
+
};
|
|
45
|
+
export type AuthenticatedProfileResult = {
|
|
46
|
+
readonly status: 'matched';
|
|
47
|
+
readonly profile: string;
|
|
48
|
+
readonly detail: string;
|
|
49
|
+
} | {
|
|
50
|
+
readonly status: 'refused';
|
|
51
|
+
readonly detail: string;
|
|
52
|
+
} | {
|
|
53
|
+
readonly status: 'unavailable';
|
|
54
|
+
readonly detail: string;
|
|
55
|
+
};
|
|
56
|
+
/** One algorithm and one call per generation-scoped evaluation; cycling is unrepresentable. */
|
|
57
|
+
export type AuthenticatedProfile = {
|
|
58
|
+
readonly algorithm: string;
|
|
59
|
+
readonly attemptLimit: 1;
|
|
60
|
+
readonly authenticate: (context: ProviderMatchRequest, profileCandidates: readonly string[]) => Promise<AuthenticatedProfileResult>;
|
|
61
|
+
};
|
|
62
|
+
export type ProviderOperationsSurface = {
|
|
63
|
+
readonly access: 'read-only' | 'read-write';
|
|
64
|
+
};
|
|
65
|
+
export interface ProviderReadOperations<O> {
|
|
66
|
+
readonly descriptor: OperationDescriptor<never, O>;
|
|
67
|
+
readonly read: (context: ProviderExecutionContext) => Promise<OperationResult<O>>;
|
|
68
|
+
}
|
|
69
|
+
export interface ProviderWriteOperations<I, O> {
|
|
70
|
+
readonly descriptor: OperationDescriptor<I, O>;
|
|
71
|
+
readonly read: (context: ProviderExecutionContext) => Promise<OperationResult<O>>;
|
|
72
|
+
readonly write: (context: ProviderExecutionContext, input: I) => Promise<OperationResult<O>>;
|
|
73
|
+
}
|
|
74
|
+
export type ProviderContractFixture = {
|
|
75
|
+
readonly profile: string;
|
|
76
|
+
readonly request: Readonly<Record<string, unknown>>;
|
|
77
|
+
readonly response: Readonly<Record<string, unknown>>;
|
|
78
|
+
};
|
|
79
|
+
export interface ProviderDefinition<TObservation = unknown, TOperations extends ProviderOperationsSurface = ProviderOperationsSurface> {
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly profileVersion: string;
|
|
82
|
+
readonly eligibleTransports: readonly ProviderTransport[];
|
|
83
|
+
readonly passiveMatchers: readonly PassiveMatcher[];
|
|
84
|
+
readonly unauthenticatedProbes: readonly UnauthenticatedProbe[];
|
|
85
|
+
readonly authenticatedProfile?: AuthenticatedProfile;
|
|
86
|
+
readonly capabilityReaders: readonly CapabilityReader[];
|
|
87
|
+
readonly observe: (context: ProviderExecutionContext) => Promise<readonly ObservationEnvelope<TObservation>[]>;
|
|
88
|
+
readonly operations: (profile: string) => TOperations;
|
|
89
|
+
readonly contractFixtures: readonly ProviderContractFixture[];
|
|
90
|
+
}
|
|
91
|
+
export type MatcherEvidence = {
|
|
92
|
+
readonly provider: string;
|
|
93
|
+
readonly profile: string | null;
|
|
94
|
+
readonly stage: 'transport-eligibility' | 'passive-facts' | 'unauthenticated-fingerprint' | 'authenticated-profile' | 'capability-read';
|
|
95
|
+
readonly source: string;
|
|
96
|
+
readonly signal: 'match' | 'mismatch' | 'unknown';
|
|
97
|
+
readonly strength: EvidenceStrength;
|
|
98
|
+
readonly detail: string;
|
|
99
|
+
};
|
|
100
|
+
type MatchResultBase = {
|
|
101
|
+
readonly score: MatcherScore;
|
|
102
|
+
readonly confidence: number;
|
|
103
|
+
readonly evidence: readonly MatcherEvidence[];
|
|
104
|
+
readonly conflicts: readonly MatcherEvidence[];
|
|
105
|
+
readonly generation: DeviceGeneration;
|
|
106
|
+
readonly physicalModemId: PhysicalModemId;
|
|
107
|
+
};
|
|
108
|
+
export type ProviderMatchResult = (MatchResultBase & {
|
|
109
|
+
readonly status: 'unsupported' | 'ambiguous';
|
|
110
|
+
readonly provider: null;
|
|
111
|
+
readonly profile: null;
|
|
112
|
+
readonly operations: null;
|
|
113
|
+
readonly writable: false;
|
|
114
|
+
}) | (MatchResultBase & {
|
|
115
|
+
readonly status: 'selected';
|
|
116
|
+
readonly provider: string;
|
|
117
|
+
readonly profile: string;
|
|
118
|
+
readonly operations: ProviderOperationsSurface;
|
|
119
|
+
readonly writable: boolean;
|
|
120
|
+
});
|
|
121
|
+
export interface ProviderMatcher {
|
|
122
|
+
match(request: ProviderMatchRequest): Promise<ProviderMatchResult>;
|
|
123
|
+
}
|
|
124
|
+
export {};
|
|
@@ -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: "unknown" | "match";
|
|
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
|
+
}
|