@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.
- package/README.md +341 -0
- package/dist/backend/at-lease.d.ts +59 -0
- package/dist/backend/at-lease.js +118 -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 +101 -0
- package/dist/backend/transition-preconditions.js +132 -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 +216 -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 +20 -0
- package/dist/index.js +27 -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 +61 -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/operation-ids.d.ts +2 -0
- package/dist/operation-ids.js +26 -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 +10 -0
- package/dist/providers/modem-manager/generic-operations.js +209 -0
- package/dist/providers/modem-manager/index.d.ts +4 -0
- package/dist/providers/modem-manager/index.js +4 -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 +41 -0
- package/dist/providers/modem-manager/provider.js +155 -0
- package/dist/providers/modem-manager/runtime-composition-operation.d.ts +32 -0
- package/dist/providers/modem-manager/runtime-composition-operation.js +151 -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 +137 -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 +171 -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 +56 -0
- package/dist/providers/zte-goform/provider.js +101 -0
- package/dist/providers/zte-goform/session.d.ts +23 -0
- package/dist/providers/zte-goform/session.js +197 -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 +88 -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 +138 -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 +6 -0
- package/dist/usb-mode/index.js +16 -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/runtime-capability.d.ts +59 -0
- package/dist/usb-mode/runtime-capability.js +157 -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 +106 -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 -236
- 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/uhubctl-power-hook.test.ts +0 -274
- package/src/backend/uhubctl-power-hook.ts +0 -377
- 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 -60
- package/src/backend/usage/policy-store.test.ts +0 -164
- package/src/backend/usage/policy-store.ts +0 -216
- package/src/backend/usage/policy-write.test.ts +0 -198
- package/src/backend/usage/policy-write.ts +0 -207
- package/src/backend/usage/proc-net-dev.test.ts +0 -56
- package/src/backend/usage/sampler.test.ts +0 -327
- package/src/backend/usage/sampler.ts +0 -282
- 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 -58
- package/src/usb-mode/ingestion.test.ts +0 -268
- package/src/usb-mode/ingestion.ts +0 -297
- package/src/usb-mode/promotion-review.ts +0 -117
- package/src/usb-mode/usb-devices-parse.ts +0 -196
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
export const RUNTIME_COMPOSITION_VENDORS = ['fibocom', 'quectel', 'simcom', 'sierra'];
|
|
2
|
+
/** Commands only: selecting a port, sending, deadlines, and retries belong to the provider. */
|
|
3
|
+
export const RUNTIME_COMPOSITION_QUERY_REGISTRY = Object.freeze({
|
|
4
|
+
fibocom: Object.freeze({ current: 'AT+GTUSBMODE?', enumerate: 'AT+GTUSBMODE=?' }),
|
|
5
|
+
quectel: Object.freeze({ current: 'AT+QCFG="usbnet"', enumerate: 'AT+QCFG=?' }),
|
|
6
|
+
simcom: Object.freeze({ current: 'AT+CUSBPIDSWITCH?', enumerate: 'AT+CUSBPIDSWITCH=?' }),
|
|
7
|
+
sierra: Object.freeze({ current: 'AT!USBCOMP?', enumerate: 'AT!USBCOMP=?' }),
|
|
8
|
+
});
|
|
9
|
+
function decimalSetCommand(prefix) {
|
|
10
|
+
return (target) => typeof target === 'number' && Number.isSafeInteger(target) && target >= 0
|
|
11
|
+
? `${prefix}${target}`
|
|
12
|
+
: undefined;
|
|
13
|
+
}
|
|
14
|
+
/** Exact reviewed SET forms. Callers still allowlist only the one enumerated target selected. */
|
|
15
|
+
export const RUNTIME_COMPOSITION_SET_REGISTRY = Object.freeze({
|
|
16
|
+
fibocom: decimalSetCommand('AT+GTUSBMODE='),
|
|
17
|
+
quectel: decimalSetCommand('AT+QCFG="usbnet",'),
|
|
18
|
+
simcom: (target) => typeof target === 'string' && /^[0-9A-Fa-f]{4}$/.test(target)
|
|
19
|
+
? `AT+CUSBPIDSWITCH=${target.toUpperCase()},1,1`
|
|
20
|
+
: undefined,
|
|
21
|
+
sierra: decimalSetCommand('AT!USBCOMP='),
|
|
22
|
+
});
|
|
23
|
+
const UNKNOWN_VENDOR = Object.freeze({
|
|
24
|
+
status: 'unknown',
|
|
25
|
+
current: null,
|
|
26
|
+
enumerated: [],
|
|
27
|
+
returnPathProven: false,
|
|
28
|
+
offerable: [],
|
|
29
|
+
reason: 'vendor-unsupported',
|
|
30
|
+
});
|
|
31
|
+
const MALFORMED_RESPONSE = Object.freeze({
|
|
32
|
+
status: 'unknown',
|
|
33
|
+
current: null,
|
|
34
|
+
enumerated: [],
|
|
35
|
+
returnPathProven: false,
|
|
36
|
+
offerable: [],
|
|
37
|
+
reason: 'malformed-response',
|
|
38
|
+
});
|
|
39
|
+
function parseDecimalDomain(domain) {
|
|
40
|
+
const values = [];
|
|
41
|
+
for (const member of domain.split(',')) {
|
|
42
|
+
const token = member.trim();
|
|
43
|
+
const range = /^(\d+)-(\d+)$/.exec(token);
|
|
44
|
+
if (range !== null) {
|
|
45
|
+
const start = Number(range[1]);
|
|
46
|
+
const end = Number(range[2]);
|
|
47
|
+
if (!Number.isSafeInteger(start) ||
|
|
48
|
+
!Number.isSafeInteger(end) ||
|
|
49
|
+
start > end ||
|
|
50
|
+
end - start > 255)
|
|
51
|
+
return undefined;
|
|
52
|
+
for (let value = start; value <= end; value += 1)
|
|
53
|
+
values.push(value);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (!/^\d+$/.test(token))
|
|
57
|
+
return undefined;
|
|
58
|
+
const value = Number(token);
|
|
59
|
+
if (!Number.isSafeInteger(value))
|
|
60
|
+
return undefined;
|
|
61
|
+
values.push(value);
|
|
62
|
+
}
|
|
63
|
+
return values.length > 0 && new Set(values).size === values.length ? values : undefined;
|
|
64
|
+
}
|
|
65
|
+
function parseFibocom(input) {
|
|
66
|
+
const current = /^\s*\+GTUSBMODE:\s*(\d+)\s*$/m.exec(input.currentResponse);
|
|
67
|
+
const enumeration = /^\s*\+GTUSBMODE:\s*\(([^)]+)\)\s*$/m.exec(input.enumerationResponse);
|
|
68
|
+
if (current === null || enumeration === null)
|
|
69
|
+
return undefined;
|
|
70
|
+
const enumerated = parseDecimalDomain(enumeration[1] ?? '');
|
|
71
|
+
return enumerated === undefined ? undefined : { current: Number(current[1]), enumerated };
|
|
72
|
+
}
|
|
73
|
+
function parseQuectel(input) {
|
|
74
|
+
const current = /^\s*\+QCFG:\s*"usbnet"\s*,\s*(\d+)\s*$/m.exec(input.currentResponse);
|
|
75
|
+
const enumeration = /^\s*\+QCFG:\s*"usbnet"\s*,\s*\(([^)]+)\)\s*$/m.exec(input.enumerationResponse);
|
|
76
|
+
if (current === null || enumeration === null)
|
|
77
|
+
return undefined;
|
|
78
|
+
const enumerated = parseDecimalDomain(enumeration[1] ?? '');
|
|
79
|
+
return enumerated === undefined ? undefined : { current: Number(current[1]), enumerated };
|
|
80
|
+
}
|
|
81
|
+
function parseSimcom(input) {
|
|
82
|
+
const current = /^\s*\+CUSBPIDSWITCH:\s*([0-9A-Fa-f]{4})\s*$/m.exec(input.currentResponse);
|
|
83
|
+
const enumeration = /\+CUSBPIDSWITCH:\s*\(([^)]+)\)\s*,\s*\(0-1\)\s*,\s*\(0-1\)/m.exec(input.enumerationResponse);
|
|
84
|
+
if (current === null || enumeration === null)
|
|
85
|
+
return undefined;
|
|
86
|
+
const tokens = (enumeration[1] ?? '').split(',').map((token) => token.trim().toUpperCase());
|
|
87
|
+
if (tokens.length === 0 || tokens.some((token) => !/^[0-9A-F]{4}$/.test(token)))
|
|
88
|
+
return undefined;
|
|
89
|
+
if (new Set(tokens).size !== tokens.length)
|
|
90
|
+
return undefined;
|
|
91
|
+
return { current: (current[1] ?? '').toUpperCase(), enumerated: tokens };
|
|
92
|
+
}
|
|
93
|
+
function parseSierra(input) {
|
|
94
|
+
const current = /^\s*!USBCOMP:\s*(\d+)(?:\s*,.*)?$/m.exec(input.currentResponse);
|
|
95
|
+
if (current === null)
|
|
96
|
+
return undefined;
|
|
97
|
+
const enumerated = Array.from(input.enumerationResponse.matchAll(/^\s*(\d+)\s*:\s*.+$/gm), (match) => Number(match[1]));
|
|
98
|
+
if (enumerated.length === 0 || new Set(enumerated).size !== enumerated.length)
|
|
99
|
+
return undefined;
|
|
100
|
+
return { current: Number(current[1]), enumerated };
|
|
101
|
+
}
|
|
102
|
+
const PARSERS = {
|
|
103
|
+
fibocom: parseFibocom,
|
|
104
|
+
quectel: parseQuectel,
|
|
105
|
+
simcom: parseSimcom,
|
|
106
|
+
sierra: parseSierra,
|
|
107
|
+
};
|
|
108
|
+
export function isRuntimeCompositionVendor(vendor) {
|
|
109
|
+
return Object.hasOwn(RUNTIME_COMPOSITION_QUERY_REGISTRY, vendor);
|
|
110
|
+
}
|
|
111
|
+
export function buildRuntimeCompositionSetCommand(vendor, target) {
|
|
112
|
+
const normalized = vendor.trim().toLowerCase();
|
|
113
|
+
return isRuntimeCompositionVendor(normalized)
|
|
114
|
+
? RUNTIME_COMPOSITION_SET_REGISTRY[normalized](target)
|
|
115
|
+
: undefined;
|
|
116
|
+
}
|
|
117
|
+
/** Parse only the vendor READ response used by the weaker post-switch proof tier. */
|
|
118
|
+
export function readRuntimeCompositionCurrent(vendor, response) {
|
|
119
|
+
const normalized = vendor.trim().toLowerCase();
|
|
120
|
+
if (!isRuntimeCompositionVendor(normalized))
|
|
121
|
+
return undefined;
|
|
122
|
+
switch (normalized) {
|
|
123
|
+
case 'fibocom': {
|
|
124
|
+
const match = /^\s*\+GTUSBMODE:\s*(\d+)\s*$/m.exec(response);
|
|
125
|
+
return match === null ? undefined : Number(match[1]);
|
|
126
|
+
}
|
|
127
|
+
case 'quectel': {
|
|
128
|
+
const match = /^\s*\+QCFG:\s*"usbnet"\s*,\s*(\d+)\s*$/m.exec(response);
|
|
129
|
+
return match === null ? undefined : Number(match[1]);
|
|
130
|
+
}
|
|
131
|
+
case 'simcom': {
|
|
132
|
+
const match = /^\s*\+CUSBPIDSWITCH:\s*([0-9A-Fa-f]{4})\s*$/m.exec(response);
|
|
133
|
+
return match === null ? undefined : (match[1] ?? '').toUpperCase();
|
|
134
|
+
}
|
|
135
|
+
case 'sierra': {
|
|
136
|
+
const match = /^\s*!USBCOMP:\s*(\d+)(?:\s*,.*)?$/m.exec(response);
|
|
137
|
+
return match === null ? undefined : Number(match[1]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Derive controls exclusively from the device's current and enumerated response text. */
|
|
142
|
+
export function resolveRuntimeCompositionCapability(input) {
|
|
143
|
+
const vendor = input.vendor.trim().toLowerCase();
|
|
144
|
+
if (!isRuntimeCompositionVendor(vendor))
|
|
145
|
+
return UNKNOWN_VENDOR;
|
|
146
|
+
const parsed = PARSERS[vendor](input);
|
|
147
|
+
if (parsed === undefined)
|
|
148
|
+
return MALFORMED_RESPONSE;
|
|
149
|
+
const returnPathProven = parsed.enumerated.includes(parsed.current);
|
|
150
|
+
return {
|
|
151
|
+
status: 'available',
|
|
152
|
+
current: parsed.current,
|
|
153
|
+
enumerated: parsed.enumerated,
|
|
154
|
+
returnPathProven,
|
|
155
|
+
offerable: returnPathProven ? parsed.enumerated : [],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** One interface line of a `usb-devices` record. */
|
|
2
|
+
export interface ParsedUsbInterface {
|
|
3
|
+
readonly interfaceClass: number;
|
|
4
|
+
readonly interfaceSubClass: number;
|
|
5
|
+
readonly interfaceProtocol: number;
|
|
6
|
+
/** The bound kernel driver, omitted when `usb-devices` reports `(none)`. */
|
|
7
|
+
readonly driver?: string;
|
|
8
|
+
}
|
|
9
|
+
/** One device block of a `usb-devices` capture. */
|
|
10
|
+
export interface ParsedUsbDevice {
|
|
11
|
+
/** Lowercase hex `xxxx:xxxx`, exactly the catalog's `vidPid` discriminator shape. */
|
|
12
|
+
readonly vidPid: string;
|
|
13
|
+
/** The `D:` line's `Cls=` byte — the device-descriptor `bDeviceClass`. */
|
|
14
|
+
readonly bDeviceClass: number;
|
|
15
|
+
readonly manufacturer?: string;
|
|
16
|
+
readonly product?: string;
|
|
17
|
+
readonly interfaces: readonly ParsedUsbInterface[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse `usb-devices` output into one record per device. Pure and total: malformed
|
|
21
|
+
* lines are skipped rather than guessed at, and a block with no `P:` line yields no
|
|
22
|
+
* record (it has no identity, so inventing one would be a lie).
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseUsbDevices(text: string): ParsedUsbDevice[];
|
|
25
|
+
/**
|
|
26
|
+
* Find the single device matching `vidPid` in a parsed capture. Returns `undefined`
|
|
27
|
+
* when there is NO match, and — deliberately — also when there is more than one: a
|
|
28
|
+
* duplicate VID:PID (this bench has two identical Huawei HiLink units) makes the
|
|
29
|
+
* selection ambiguous, and an ambiguous selection must refuse rather than pick the
|
|
30
|
+
* first. The caller turns that into a typed refusal.
|
|
31
|
+
*/
|
|
32
|
+
export declare function selectUniqueDevice(devices: readonly ParsedUsbDevice[], vidPid: string): {
|
|
33
|
+
readonly device: ParsedUsbDevice;
|
|
34
|
+
} | {
|
|
35
|
+
readonly ambiguousMatches: number;
|
|
36
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Parsing `usb-devices` text — the ONLY per-interface descriptor source inside a
|
|
2
|
+
// certification bundle.
|
|
3
|
+
//
|
|
4
|
+
// A base certification bundle (`certify <slot>` with no `--transition`) carries no
|
|
5
|
+
// structured descriptors at all: it holds `lsusb -v` and `usb-devices` as raw text plus
|
|
6
|
+
// the slot's udev property map. Authoring a classifier fixture or a catalog entry from
|
|
7
|
+
// such a bundle therefore requires reading the descriptors back out of that text, and
|
|
8
|
+
// `usb-devices` is the right half to read — it is line-oriented, one fixed-width record
|
|
9
|
+
// per device, and it names each interface's BOUND KERNEL DRIVER, which `lsusb -v` does
|
|
10
|
+
// not. The driver is not optional detail here: `classifyDevice` decides `mm-managed` vs
|
|
11
|
+
// `router-mode` partly on `qmi_wwan` / `cdc_ether` / `option` bindings.
|
|
12
|
+
//
|
|
13
|
+
// The parser is pure and total: unparseable lines are SKIPPED, never guessed at, and a
|
|
14
|
+
// device that yields no interfaces still yields a record (callers decide whether an
|
|
15
|
+
// interface-less device is usable — this file never makes that judgement).
|
|
16
|
+
//
|
|
17
|
+
// Record shape (`usb-devices`, one blank-line-separated block per device):
|
|
18
|
+
// T: Bus=04 Lev=03 Prnt=03 Port=03 Cnt=01 Dev#= 7 Spd=480 MxCh= 0
|
|
19
|
+
// D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
|
|
20
|
+
// P: Vendor=2c7c ProdID=0801 Rev=05.04
|
|
21
|
+
// S: Manufacturer=Quectel
|
|
22
|
+
// S: Product=RM530N-GL
|
|
23
|
+
// I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan
|
|
24
|
+
/** Read `Key=value` from a `usb-devices` line; `undefined` when the key is absent. */
|
|
25
|
+
function field(line, key) {
|
|
26
|
+
// Values are whitespace-delimited and may be preceded by padding spaces (`Dev#= 7`).
|
|
27
|
+
// `Cls=ff(vend.)` carries a trailing gloss, stripped by the hex/number parsers below.
|
|
28
|
+
const match = new RegExp(`${key}=\\s*(\\S+)`).exec(line);
|
|
29
|
+
return match?.[1];
|
|
30
|
+
}
|
|
31
|
+
/** Parse a hex byte field, tolerating `usb-devices`' `ff(vend.)` gloss suffix. */
|
|
32
|
+
function hexByte(line, key) {
|
|
33
|
+
const raw = field(line, key);
|
|
34
|
+
if (raw === undefined) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const digits = /^[0-9a-fA-F]{1,2}/.exec(raw)?.[0];
|
|
38
|
+
if (digits === undefined) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const value = Number.parseInt(digits, 16);
|
|
42
|
+
return Number.isNaN(value) ? undefined : value;
|
|
43
|
+
}
|
|
44
|
+
/** Parse an `S: Manufacturer=…` style line into its `[key, value]` pair. */
|
|
45
|
+
function stringField(line) {
|
|
46
|
+
const eq = line.indexOf('=');
|
|
47
|
+
if (eq < 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const key = line.slice(3, eq).trim();
|
|
51
|
+
const value = line.slice(eq + 1).trim();
|
|
52
|
+
return key === '' || value === '' ? undefined : [key, value];
|
|
53
|
+
}
|
|
54
|
+
function emptyAccumulator() {
|
|
55
|
+
return { interfaces: [] };
|
|
56
|
+
}
|
|
57
|
+
function finish(acc, out) {
|
|
58
|
+
// A record with no `P:` line is not a device — never synthesise an identity for it.
|
|
59
|
+
if (acc.vidPid === undefined) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
out.push({
|
|
63
|
+
vidPid: acc.vidPid,
|
|
64
|
+
bDeviceClass: acc.bDeviceClass ?? 0,
|
|
65
|
+
interfaces: acc.interfaces,
|
|
66
|
+
...(acc.manufacturer !== undefined ? { manufacturer: acc.manufacturer } : {}),
|
|
67
|
+
...(acc.product !== undefined ? { product: acc.product } : {}),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function applyProductLine(line, acc) {
|
|
71
|
+
const vendor = field(line, 'Vendor');
|
|
72
|
+
const product = field(line, 'ProdID');
|
|
73
|
+
if (vendor !== undefined && product !== undefined) {
|
|
74
|
+
acc.vidPid = `${vendor.toLowerCase()}:${product.toLowerCase()}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function applyStringLine(line, acc) {
|
|
78
|
+
const pair = stringField(line);
|
|
79
|
+
if (pair === undefined) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const [key, value] = pair;
|
|
83
|
+
if (key === 'Manufacturer') {
|
|
84
|
+
acc.manufacturer = value;
|
|
85
|
+
}
|
|
86
|
+
else if (key === 'Product') {
|
|
87
|
+
acc.product = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function applyInterfaceLine(line, acc) {
|
|
91
|
+
const interfaceClass = hexByte(line, 'Cls');
|
|
92
|
+
const interfaceSubClass = hexByte(line, 'Sub');
|
|
93
|
+
const interfaceProtocol = hexByte(line, 'Prot');
|
|
94
|
+
if (interfaceClass === undefined ||
|
|
95
|
+
interfaceSubClass === undefined ||
|
|
96
|
+
interfaceProtocol === undefined) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const driver = field(line, 'Driver');
|
|
100
|
+
acc.interfaces.push({
|
|
101
|
+
interfaceClass,
|
|
102
|
+
interfaceSubClass,
|
|
103
|
+
interfaceProtocol,
|
|
104
|
+
...(driver !== undefined && driver !== '(none)' ? { driver } : {}),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Parse `usb-devices` output into one record per device. Pure and total: malformed
|
|
109
|
+
* lines are skipped rather than guessed at, and a block with no `P:` line yields no
|
|
110
|
+
* record (it has no identity, so inventing one would be a lie).
|
|
111
|
+
*/
|
|
112
|
+
export function parseUsbDevices(text) {
|
|
113
|
+
const out = [];
|
|
114
|
+
let acc = emptyAccumulator();
|
|
115
|
+
for (const line of text.split('\n')) {
|
|
116
|
+
// A `T:` line opens a new device record; `usb-devices` also blank-line-separates
|
|
117
|
+
// them, but the topology line is the reliable delimiter (blank lines are optional
|
|
118
|
+
// in some kernels' output).
|
|
119
|
+
if (line.startsWith('T:')) {
|
|
120
|
+
finish(acc, out);
|
|
121
|
+
acc = emptyAccumulator();
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (line.startsWith('D:')) {
|
|
125
|
+
const deviceClass = hexByte(line, 'Cls');
|
|
126
|
+
if (deviceClass !== undefined) {
|
|
127
|
+
acc.bDeviceClass = deviceClass;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (line.startsWith('P:')) {
|
|
131
|
+
applyProductLine(line, acc);
|
|
132
|
+
}
|
|
133
|
+
else if (line.startsWith('S:')) {
|
|
134
|
+
applyStringLine(line, acc);
|
|
135
|
+
}
|
|
136
|
+
else if (line.startsWith('I:')) {
|
|
137
|
+
applyInterfaceLine(line, acc);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
finish(acc, out);
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Find the single device matching `vidPid` in a parsed capture. Returns `undefined`
|
|
145
|
+
* when there is NO match, and — deliberately — also when there is more than one: a
|
|
146
|
+
* duplicate VID:PID (this bench has two identical Huawei HiLink units) makes the
|
|
147
|
+
* selection ambiguous, and an ambiguous selection must refuse rather than pick the
|
|
148
|
+
* first. The caller turns that into a typed refusal.
|
|
149
|
+
*/
|
|
150
|
+
export function selectUniqueDevice(devices, vidPid) {
|
|
151
|
+
const matches = devices.filter((d) => d.vidPid === vidPid);
|
|
152
|
+
const only = matches[0];
|
|
153
|
+
if (matches.length === 1 && only !== undefined) {
|
|
154
|
+
return { device: only };
|
|
155
|
+
}
|
|
156
|
+
return { ambiguousMatches: matches.length };
|
|
157
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DbusTransport } from '../transport/index.js';
|
|
2
|
+
import type { UssdRepliedState } from './session.js';
|
|
3
|
+
/** `MMModem3gppUssdSessionState`. */
|
|
4
|
+
export declare const USSD_STATE_UNKNOWN = 0;
|
|
5
|
+
export declare const USSD_STATE_IDLE = 1;
|
|
6
|
+
export declare const USSD_STATE_ACTIVE = 2;
|
|
7
|
+
export declare const USSD_STATE_USER_RESPONSE = 3;
|
|
8
|
+
/**
|
|
9
|
+
* Decode MM's post-call session state. `UNKNOWN` folds onto `released` with the
|
|
10
|
+
* rest: an unreadable state must close the session rather than leave the operator
|
|
11
|
+
* looking at a dialogue nothing can advance.
|
|
12
|
+
*/
|
|
13
|
+
export declare function decodeRepliedState(state: number): UssdRepliedState;
|
|
14
|
+
export interface UssdCallTarget {
|
|
15
|
+
readonly transport: DbusTransport;
|
|
16
|
+
readonly destination: string;
|
|
17
|
+
readonly modem: string;
|
|
18
|
+
readonly timeoutMs: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function callInitiate(target: UssdCallTarget, ussdCommand: string): Promise<string>;
|
|
21
|
+
export declare function callRespond(target: UssdCallTarget, ussdResponse: string): Promise<string>;
|
|
22
|
+
export declare function callCancel(target: UssdCallTarget): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Read the post-call session state.
|
|
25
|
+
*
|
|
26
|
+
* A targeted `Properties.Get` rather than a `GetManagedObjects` sweep: this runs
|
|
27
|
+
* after every network round-trip, and the whole-tree read is the most expensive
|
|
28
|
+
* call in the package. `unknown` on anything unreadable — the caller treats that
|
|
29
|
+
* as "the network released the session", which is the conservative direction (it
|
|
30
|
+
* closes a session rather than leaving one the operator cannot see).
|
|
31
|
+
*/
|
|
32
|
+
export declare function readUssdState(target: UssdCallTarget): Promise<number>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// The four D-Bus calls the USSD adapter makes, and nothing else.
|
|
2
|
+
//
|
|
3
|
+
// Split from the adapter so the session machinery above can be read without the
|
|
4
|
+
// marshalling below, and so a call's shape (interface, member, signature) is
|
|
5
|
+
// stated once in one place.
|
|
6
|
+
//
|
|
7
|
+
// CARRIER TEXT DISCIPLINE: `Initiate` and `Respond` both take and return operator
|
|
8
|
+
// text, and neither the command nor the reply may ever reach a log line. Nothing
|
|
9
|
+
// in this file logs, and every error raised here is re-thrown untouched so the
|
|
10
|
+
// classifier — not a string built around the payload — decides what the caller is
|
|
11
|
+
// told.
|
|
12
|
+
import { MODEM3GPP_USSD_IFACE, PROPERTIES_IFACE } from '../backend/constants.js';
|
|
13
|
+
/** `MMModem3gppUssdSessionState`. */
|
|
14
|
+
export const USSD_STATE_UNKNOWN = 0;
|
|
15
|
+
export const USSD_STATE_IDLE = 1;
|
|
16
|
+
export const USSD_STATE_ACTIVE = 2;
|
|
17
|
+
export const USSD_STATE_USER_RESPONSE = 3;
|
|
18
|
+
/**
|
|
19
|
+
* Decode MM's post-call session state. `UNKNOWN` folds onto `released` with the
|
|
20
|
+
* rest: an unreadable state must close the session rather than leave the operator
|
|
21
|
+
* looking at a dialogue nothing can advance.
|
|
22
|
+
*/
|
|
23
|
+
export function decodeRepliedState(state) {
|
|
24
|
+
if (state === USSD_STATE_USER_RESPONSE) {
|
|
25
|
+
return 'awaiting-reply';
|
|
26
|
+
}
|
|
27
|
+
return state === USSD_STATE_ACTIVE ? 'active' : 'released';
|
|
28
|
+
}
|
|
29
|
+
function firstString(body) {
|
|
30
|
+
const value = body[0];
|
|
31
|
+
return typeof value === 'string' ? value : '';
|
|
32
|
+
}
|
|
33
|
+
export async function callInitiate(target, ussdCommand) {
|
|
34
|
+
const reply = await target.transport.callMethod({
|
|
35
|
+
destination: target.destination,
|
|
36
|
+
path: target.modem,
|
|
37
|
+
interface: MODEM3GPP_USSD_IFACE,
|
|
38
|
+
member: 'Initiate',
|
|
39
|
+
signature: 's',
|
|
40
|
+
args: [ussdCommand],
|
|
41
|
+
timeoutMs: target.timeoutMs,
|
|
42
|
+
});
|
|
43
|
+
return firstString(reply.body);
|
|
44
|
+
}
|
|
45
|
+
export async function callRespond(target, ussdResponse) {
|
|
46
|
+
const reply = await target.transport.callMethod({
|
|
47
|
+
destination: target.destination,
|
|
48
|
+
path: target.modem,
|
|
49
|
+
interface: MODEM3GPP_USSD_IFACE,
|
|
50
|
+
member: 'Respond',
|
|
51
|
+
signature: 's',
|
|
52
|
+
args: [ussdResponse],
|
|
53
|
+
timeoutMs: target.timeoutMs,
|
|
54
|
+
});
|
|
55
|
+
return firstString(reply.body);
|
|
56
|
+
}
|
|
57
|
+
export async function callCancel(target) {
|
|
58
|
+
await target.transport.callMethod({
|
|
59
|
+
destination: target.destination,
|
|
60
|
+
path: target.modem,
|
|
61
|
+
interface: MODEM3GPP_USSD_IFACE,
|
|
62
|
+
member: 'Cancel',
|
|
63
|
+
timeoutMs: target.timeoutMs,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Read the post-call session state.
|
|
68
|
+
*
|
|
69
|
+
* A targeted `Properties.Get` rather than a `GetManagedObjects` sweep: this runs
|
|
70
|
+
* after every network round-trip, and the whole-tree read is the most expensive
|
|
71
|
+
* call in the package. `unknown` on anything unreadable — the caller treats that
|
|
72
|
+
* as "the network released the session", which is the conservative direction (it
|
|
73
|
+
* closes a session rather than leaving one the operator cannot see).
|
|
74
|
+
*/
|
|
75
|
+
export async function readUssdState(target) {
|
|
76
|
+
try {
|
|
77
|
+
const reply = await target.transport.callMethod({
|
|
78
|
+
destination: target.destination,
|
|
79
|
+
path: target.modem,
|
|
80
|
+
interface: PROPERTIES_IFACE,
|
|
81
|
+
member: 'Get',
|
|
82
|
+
signature: 'ss',
|
|
83
|
+
args: [MODEM3GPP_USSD_IFACE, 'State'],
|
|
84
|
+
timeoutMs: target.timeoutMs,
|
|
85
|
+
});
|
|
86
|
+
const wrapped = reply.body[0];
|
|
87
|
+
if (typeof wrapped === 'number') {
|
|
88
|
+
return wrapped;
|
|
89
|
+
}
|
|
90
|
+
const inner = wrapped?.value;
|
|
91
|
+
return typeof inner === 'number' ? inner : USSD_STATE_UNKNOWN;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return USSD_STATE_UNKNOWN;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { callCancel, callInitiate, callRespond, decodeRepliedState, readUssdState, USSD_STATE_ACTIVE, USSD_STATE_IDLE, USSD_STATE_UNKNOWN, USSD_STATE_USER_RESPONSE, type UssdCallTarget, } from './calls.js';
|
|
2
|
+
export { MmUssd, type MmUssdDeps, type UssdScheduler, type UssdTimerHandle, type UssdVerbResult, } from './mm-ussd.js';
|
|
3
|
+
export { classifyUssdFailure, isPacketSwitchedOnly, USSD_REFUSAL_REASONS, type UssdRefusalReason, type UssdRegistrationFacts, } from './refusal.js';
|
|
4
|
+
export { decodeAccessTechnologies, readUssdRegistrationFacts, registrationFactsFromTree, UNKNOWN_REGISTRATION, } from './registration.js';
|
|
5
|
+
export { IDLE_SESSION, isUssdSessionOpen, reduceUssdSession, USSD_SESSION_OUTCOMES, USSD_SESSION_STATES, type UssdRepliedState, type UssdSessionEvent, type UssdSessionOutcome, type UssdSessionSnapshot, type UssdSessionState, type UssdTransition, } from './session.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The gated USSD capability module — session state machine, refusal taxonomy, and
|
|
2
|
+
// the ModemManager `Modem3gpp.Ussd` adapter.
|
|
3
|
+
//
|
|
4
|
+
// GATED: nothing here runs unless the operator has enabled the `ussd` capability
|
|
5
|
+
// module and the modem positively advertises the interface (`../capability`).
|
|
6
|
+
// LEASE-ONLY: a USSD session cannot re-register the radio, so it takes the
|
|
7
|
+
// per-modem mutation lease and is NOT journaled.
|
|
8
|
+
export { callCancel, callInitiate, callRespond, decodeRepliedState, readUssdState, USSD_STATE_ACTIVE, USSD_STATE_IDLE, USSD_STATE_UNKNOWN, USSD_STATE_USER_RESPONSE, } from './calls.js';
|
|
9
|
+
export { MmUssd, } from './mm-ussd.js';
|
|
10
|
+
export { classifyUssdFailure, isPacketSwitchedOnly, USSD_REFUSAL_REASONS, } from './refusal.js';
|
|
11
|
+
export { decodeAccessTechnologies, readUssdRegistrationFacts, registrationFactsFromTree, UNKNOWN_REGISTRATION, } from './registration.js';
|
|
12
|
+
export { IDLE_SESSION, isUssdSessionOpen, reduceUssdSession, USSD_SESSION_OUTCOMES, USSD_SESSION_STATES, } from './session.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ModemActor } from '../backend/modem-actor.js';
|
|
2
|
+
import type { ModemRef } from '../ports/index.js';
|
|
3
|
+
import type { DbusTransport } from '../transport/index.js';
|
|
4
|
+
import { type UssdRefusalReason } from './refusal.js';
|
|
5
|
+
import { type UssdSessionSnapshot } from './session.js';
|
|
6
|
+
export interface UssdTimerHandle {
|
|
7
|
+
cancel(): void;
|
|
8
|
+
}
|
|
9
|
+
export type UssdScheduler = (delayMs: number, run: () => void) => UssdTimerHandle;
|
|
10
|
+
export interface UssdVerbResult {
|
|
11
|
+
readonly ok: boolean;
|
|
12
|
+
readonly snapshot: UssdSessionSnapshot;
|
|
13
|
+
/** Carrier text. Redacted by key everywhere it is serialized. */
|
|
14
|
+
readonly ussdReply?: string;
|
|
15
|
+
readonly refusal?: UssdRefusalReason;
|
|
16
|
+
}
|
|
17
|
+
export interface MmUssdDeps {
|
|
18
|
+
readonly transport: DbusTransport;
|
|
19
|
+
readonly actor: ModemActor;
|
|
20
|
+
readonly destination?: string;
|
|
21
|
+
readonly resolveStableKey: (modem: ModemRef) => string;
|
|
22
|
+
readonly callTimeoutMs?: number;
|
|
23
|
+
readonly sessionIdleTimeoutMs?: number;
|
|
24
|
+
readonly scheduler?: UssdScheduler;
|
|
25
|
+
/** Notified on every stored-state change, so a UI can follow a session. */
|
|
26
|
+
readonly onSessionChange?: (stableKey: string, snapshot: UssdSessionSnapshot) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare class MmUssd {
|
|
29
|
+
#private;
|
|
30
|
+
constructor(deps: MmUssdDeps);
|
|
31
|
+
snapshot(modem: ModemRef): UssdSessionSnapshot;
|
|
32
|
+
initiate(modem: ModemRef, ussdCommand: string): Promise<UssdVerbResult>;
|
|
33
|
+
respond(modem: ModemRef, ussdResponse: string): Promise<UssdVerbResult>;
|
|
34
|
+
cancel(modem: ModemRef): Promise<UssdVerbResult>;
|
|
35
|
+
/** Drop every timer. A live session on the modem is NOT cancelled by this. */
|
|
36
|
+
stop(): void;
|
|
37
|
+
}
|