@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,155 @@
|
|
|
1
|
+
import { createMmDbusBackend, fetchManagedObjects, MM_BUS_NAME, MmLocation, ModemActor, } from '../../backend/index.js';
|
|
2
|
+
import { BAND_CERTIFICATION_CATALOG, findBandCertification, } from '../../band/index.js';
|
|
3
|
+
import { epochMillis, sourceEpoch, stableKeyFromPhysicalModemId, } from '../../domain/index.js';
|
|
4
|
+
import { unavailableObservation } from '../../observations/index.js';
|
|
5
|
+
import { MmUssd } from '../../ussd/index.js';
|
|
6
|
+
import { mapModemManagerError } from './errors.js';
|
|
7
|
+
import { createGenericOperations } from './generic-operations.js';
|
|
8
|
+
import { ModemManagerModuleOperations } from './module-operations.js';
|
|
9
|
+
import { buildModemManagerSnapshot } from './snapshot.js';
|
|
10
|
+
const PROFILE = 'generic-mm';
|
|
11
|
+
export class ModemManagerProvider {
|
|
12
|
+
definition;
|
|
13
|
+
#transport;
|
|
14
|
+
#destination;
|
|
15
|
+
#now;
|
|
16
|
+
#backend;
|
|
17
|
+
#bandCatalog;
|
|
18
|
+
#bandSku;
|
|
19
|
+
#stableKeyByPath = new Map();
|
|
20
|
+
#moduleOperations;
|
|
21
|
+
#startPromise;
|
|
22
|
+
#epoch = 1;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.#transport = options.transport;
|
|
25
|
+
this.#destination = options.destination ?? MM_BUS_NAME;
|
|
26
|
+
this.#now = options.now ?? Date.now;
|
|
27
|
+
this.#bandCatalog = options.bandCertificationCatalog ?? BAND_CERTIFICATION_CATALOG;
|
|
28
|
+
this.#bandSku = options.bandSku ?? (() => undefined);
|
|
29
|
+
const actor = new ModemActor(options.quiesce);
|
|
30
|
+
const resolveStableKey = (modem) => this.#stableKeyByPath.get(modem) ?? modem;
|
|
31
|
+
this.#backend = createMmDbusBackend({
|
|
32
|
+
transport: this.#transport,
|
|
33
|
+
destination: this.#destination,
|
|
34
|
+
actor,
|
|
35
|
+
now: this.#now,
|
|
36
|
+
});
|
|
37
|
+
const location = new MmLocation({
|
|
38
|
+
transport: this.#transport,
|
|
39
|
+
actor,
|
|
40
|
+
destination: this.#destination,
|
|
41
|
+
resolveStableKey,
|
|
42
|
+
now: this.#now,
|
|
43
|
+
});
|
|
44
|
+
const ussd = new MmUssd({
|
|
45
|
+
transport: this.#transport,
|
|
46
|
+
actor,
|
|
47
|
+
destination: this.#destination,
|
|
48
|
+
resolveStableKey,
|
|
49
|
+
});
|
|
50
|
+
this.#moduleOperations = new ModemManagerModuleOperations({
|
|
51
|
+
transport: this.#transport,
|
|
52
|
+
destination: this.#destination,
|
|
53
|
+
location,
|
|
54
|
+
ussd,
|
|
55
|
+
now: this.#now,
|
|
56
|
+
readSnapshot: (context) => this.readSnapshot(context),
|
|
57
|
+
});
|
|
58
|
+
const operations = {
|
|
59
|
+
access: 'read-write',
|
|
60
|
+
...createGenericOperations({
|
|
61
|
+
backend: this.#backend,
|
|
62
|
+
readSnapshot: (context) => this.readSnapshot(context),
|
|
63
|
+
...(options.runtimeComposition === undefined
|
|
64
|
+
? {}
|
|
65
|
+
: { runtimeComposition: options.runtimeComposition }),
|
|
66
|
+
}),
|
|
67
|
+
...this.#moduleOperations.operations,
|
|
68
|
+
};
|
|
69
|
+
this.definition = {
|
|
70
|
+
id: 'modemmanager',
|
|
71
|
+
profileVersion: '1',
|
|
72
|
+
eligibleTransports: ['modemmanager'],
|
|
73
|
+
passiveMatchers: [],
|
|
74
|
+
unauthenticatedProbes: [
|
|
75
|
+
{ id: 'object-manager-modem', run: (request) => this.#probe(request) },
|
|
76
|
+
],
|
|
77
|
+
capabilityReaders: [
|
|
78
|
+
{ id: 'runtime-modem-interface', read: (context) => this.#capability(context) },
|
|
79
|
+
],
|
|
80
|
+
observe: (context) => this.#observeNormalized(context),
|
|
81
|
+
operations: () => operations,
|
|
82
|
+
contractFixtures: [],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
start() {
|
|
86
|
+
this.#startPromise ??= this.#backend.start();
|
|
87
|
+
return this.#startPromise;
|
|
88
|
+
}
|
|
89
|
+
observe(listener) {
|
|
90
|
+
return this.#backend.observe(listener);
|
|
91
|
+
}
|
|
92
|
+
async stop() {
|
|
93
|
+
await this.#moduleOperations.stop();
|
|
94
|
+
await this.#backend.stop();
|
|
95
|
+
}
|
|
96
|
+
async readSnapshot(context) {
|
|
97
|
+
try {
|
|
98
|
+
await this.start();
|
|
99
|
+
const tree = await fetchManagedObjects(this.#transport, this.#destination);
|
|
100
|
+
const snapshot = buildModemManagerSnapshot(tree, context, this.#now, this.#epoch, this.#bandCertification(context));
|
|
101
|
+
if (snapshot === undefined)
|
|
102
|
+
return { ok: false, reason: 'not-found' };
|
|
103
|
+
this.#stableKeyByPath.set(snapshot.modemPath, `modem:${context.physicalModemId}`);
|
|
104
|
+
return { ok: true, ...snapshot };
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return { ok: false, reason: mapModemManagerError(error).reason };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
#bandCertification(context) {
|
|
111
|
+
const sku = this.#bandSku(context);
|
|
112
|
+
return sku === undefined ? undefined : findBandCertification(this.#bandCatalog, sku);
|
|
113
|
+
}
|
|
114
|
+
async #probe(request) {
|
|
115
|
+
const snapshot = await this.readSnapshot({ ...request, profile: PROFILE });
|
|
116
|
+
return {
|
|
117
|
+
signal: snapshot.ok
|
|
118
|
+
? 'match'
|
|
119
|
+
: snapshot.reason === 'not-found'
|
|
120
|
+
? 'mismatch'
|
|
121
|
+
: 'unknown',
|
|
122
|
+
strength: 'strong',
|
|
123
|
+
profiles: [PROFILE],
|
|
124
|
+
detail: snapshot.ok ? 'runtime-modem-interface-present' : snapshot.reason,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async #capability(context) {
|
|
128
|
+
const snapshot = await this.readSnapshot(context);
|
|
129
|
+
return {
|
|
130
|
+
signal: snapshot.ok
|
|
131
|
+
? 'match'
|
|
132
|
+
: snapshot.reason === 'not-found'
|
|
133
|
+
? 'mismatch'
|
|
134
|
+
: 'unknown',
|
|
135
|
+
strength: 'strong',
|
|
136
|
+
detail: snapshot.ok ? 'generic-controls-derived-from-runtime-properties' : snapshot.reason,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async #observeNormalized(context) {
|
|
140
|
+
const snapshot = await this.readSnapshot(context);
|
|
141
|
+
if (snapshot.ok)
|
|
142
|
+
return [snapshot.observation];
|
|
143
|
+
return [
|
|
144
|
+
unavailableObservation('modemmanager', {
|
|
145
|
+
stableKey: stableKeyFromPhysicalModemId(context.physicalModemId),
|
|
146
|
+
generation: context.generation,
|
|
147
|
+
sourceEpoch: sourceEpoch(this.#epoch),
|
|
148
|
+
observedAt: epochMillis(this.#now()),
|
|
149
|
+
}, snapshot.reason === 'not-found' ? 'device-absent' : 'provider-unavailable'),
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export function createModemManagerProvider(options) {
|
|
154
|
+
return new ModemManagerProvider(options);
|
|
155
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type AtCommandSender, type UsbModeTransitionOutcome } from '../../backend/index.js';
|
|
2
|
+
import { type RuntimeCompositionCapability, type RuntimeCompositionMode } from '../../usb-mode/index.js';
|
|
3
|
+
import type { ProviderExecutionContext } from '../contracts.js';
|
|
4
|
+
import type { ContextWriteOperation } from './types.js';
|
|
5
|
+
export declare const RUNTIME_COMPOSITION_SUPPRESSIONS: readonly ['unknown-vendor', 'no-return-path', 'blocked-by-state', 'provisioning-disabled'];
|
|
6
|
+
export type RuntimeCompositionSuppression = (typeof RUNTIME_COMPOSITION_SUPPRESSIONS)[number];
|
|
7
|
+
export type RuntimeCompositionState = {
|
|
8
|
+
readonly status: 'available';
|
|
9
|
+
readonly current: RuntimeCompositionMode;
|
|
10
|
+
readonly enumerated: readonly RuntimeCompositionMode[];
|
|
11
|
+
readonly offerable: readonly RuntimeCompositionMode[];
|
|
12
|
+
} | {
|
|
13
|
+
readonly status: 'suppressed';
|
|
14
|
+
readonly reason: RuntimeCompositionSuppression;
|
|
15
|
+
readonly detail: string;
|
|
16
|
+
readonly current: RuntimeCompositionMode | null;
|
|
17
|
+
readonly enumerated: readonly RuntimeCompositionMode[];
|
|
18
|
+
readonly offerable: readonly [];
|
|
19
|
+
};
|
|
20
|
+
export type RuntimeCompositionOperationDeps = {
|
|
21
|
+
readonly vendor: (context: ProviderExecutionContext) => string | Promise<string>;
|
|
22
|
+
readonly provisioningEnabled: (context: ProviderExecutionContext) => boolean | Promise<boolean>;
|
|
23
|
+
readonly blockedReason: (context: ProviderExecutionContext) => string | undefined | Promise<string | undefined>;
|
|
24
|
+
readonly atSender: AtCommandSender;
|
|
25
|
+
readonly transition: (context: ProviderExecutionContext, capability: Extract<RuntimeCompositionCapability, {
|
|
26
|
+
readonly status: 'available';
|
|
27
|
+
}>, target: RuntimeCompositionMode) => Promise<UsbModeTransitionOutcome>;
|
|
28
|
+
};
|
|
29
|
+
export interface RuntimeCompositionOperation extends ContextWriteOperation<RuntimeCompositionMode, RuntimeCompositionState> {
|
|
30
|
+
capability(context: ProviderExecutionContext): Promise<RuntimeCompositionState>;
|
|
31
|
+
}
|
|
32
|
+
export declare function createRuntimeCompositionOperation(deps: RuntimeCompositionOperationDeps | undefined): RuntimeCompositionOperation;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { AtCommandLease, computeAtAllowlist, } from '../../backend/index.js';
|
|
2
|
+
import { classifyOperationCompletion, defineOperationDescriptor, } from '../../domain/index.js';
|
|
3
|
+
import { isRuntimeCompositionVendor, RUNTIME_COMPOSITION_QUERY_REGISTRY, resolveRuntimeCompositionCapability, } from '../../usb-mode/index.js';
|
|
4
|
+
export const RUNTIME_COMPOSITION_SUPPRESSIONS = [
|
|
5
|
+
'unknown-vendor',
|
|
6
|
+
'no-return-path',
|
|
7
|
+
'blocked-by-state',
|
|
8
|
+
'provisioning-disabled',
|
|
9
|
+
];
|
|
10
|
+
const OPERATION_ID = 'modemmanager.usb-composition';
|
|
11
|
+
function suppressed(reason, detail, capability) {
|
|
12
|
+
return {
|
|
13
|
+
status: 'suppressed',
|
|
14
|
+
reason,
|
|
15
|
+
detail,
|
|
16
|
+
current: capability?.current ?? null,
|
|
17
|
+
enumerated: capability?.enumerated ?? [],
|
|
18
|
+
offerable: [],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function descriptorFor(state) {
|
|
22
|
+
const available = state.status === 'available';
|
|
23
|
+
return defineOperationDescriptor({
|
|
24
|
+
id: OPERATION_ID,
|
|
25
|
+
support: {
|
|
26
|
+
read: { supported: true },
|
|
27
|
+
write: available ? { supported: true } : { supported: false, reason: state.reason },
|
|
28
|
+
},
|
|
29
|
+
authority: 'provider',
|
|
30
|
+
provider: 'modemmanager',
|
|
31
|
+
constraints: {
|
|
32
|
+
kind: 'allowed-values',
|
|
33
|
+
values: available ? state.offerable : [],
|
|
34
|
+
},
|
|
35
|
+
livePreconditions: [
|
|
36
|
+
'modem-present',
|
|
37
|
+
'runtime-interface-present',
|
|
38
|
+
'identity-confident',
|
|
39
|
+
'streaming-interlock-open',
|
|
40
|
+
],
|
|
41
|
+
availability: available ? { state: 'available' } : { state: 'refused', reason: state.reason },
|
|
42
|
+
mutationImpact: 'disruptive',
|
|
43
|
+
retryClass: 'never',
|
|
44
|
+
readback: {
|
|
45
|
+
required: true,
|
|
46
|
+
reason: 'device-reported-composition',
|
|
47
|
+
matches: (input, value) => value.status === 'available' && Object.is(input, value.current),
|
|
48
|
+
},
|
|
49
|
+
rollback: { required: true, reason: 'restore-previous-composition' },
|
|
50
|
+
journal: { required: true, reason: 'composition-reenumeration' },
|
|
51
|
+
admission: { required: true, reason: 'provider-mutation' },
|
|
52
|
+
evidence: { profiles: ['generic-mm'], firmware: [] },
|
|
53
|
+
confidence: available ? 'high' : 'unknown',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function result(context, completion) {
|
|
57
|
+
return classifyOperationCompletion({
|
|
58
|
+
operation: 'write',
|
|
59
|
+
completionGeneration: context.generation,
|
|
60
|
+
currentGeneration: context.generation,
|
|
61
|
+
completion,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function disabledOperation() {
|
|
65
|
+
const state = {
|
|
66
|
+
status: 'suppressed',
|
|
67
|
+
reason: 'provisioning-disabled',
|
|
68
|
+
detail: 'USB composition provisioning is not configured',
|
|
69
|
+
current: null,
|
|
70
|
+
enumerated: [],
|
|
71
|
+
offerable: [],
|
|
72
|
+
};
|
|
73
|
+
const descriptor = descriptorFor(state);
|
|
74
|
+
return {
|
|
75
|
+
descriptor,
|
|
76
|
+
describe: () => Promise.resolve(descriptor),
|
|
77
|
+
capability: () => Promise.resolve(state),
|
|
78
|
+
read: (context) => Promise.resolve(result(context, { status: 'applied', value: state })),
|
|
79
|
+
write: (context) => Promise.resolve(result(context, { status: 'refused', reason: state.reason })),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export function createRuntimeCompositionOperation(deps) {
|
|
83
|
+
if (deps === undefined)
|
|
84
|
+
return disabledOperation();
|
|
85
|
+
const capability = async (context) => {
|
|
86
|
+
const vendor = (await deps.vendor(context)).trim().toLowerCase();
|
|
87
|
+
if (!isRuntimeCompositionVendor(vendor))
|
|
88
|
+
return suppressed('unknown-vendor', `No reviewed composition query exists for ${vendor}`);
|
|
89
|
+
if (!(await deps.provisioningEnabled(context)))
|
|
90
|
+
return suppressed('provisioning-disabled', 'USB composition provisioning is disabled');
|
|
91
|
+
const blocked = await deps.blockedReason(context);
|
|
92
|
+
if (blocked !== undefined)
|
|
93
|
+
return suppressed('blocked-by-state', blocked);
|
|
94
|
+
const queries = RUNTIME_COMPOSITION_QUERY_REGISTRY[vendor];
|
|
95
|
+
const lease = new AtCommandLease({
|
|
96
|
+
sender: deps.atSender,
|
|
97
|
+
allowlist: computeAtAllowlist([]),
|
|
98
|
+
});
|
|
99
|
+
const current = await lease.run(queries.current);
|
|
100
|
+
const enumeration = await lease.run(queries.enumerate);
|
|
101
|
+
const resolved = resolveRuntimeCompositionCapability({
|
|
102
|
+
vendor,
|
|
103
|
+
currentResponse: current.raw,
|
|
104
|
+
enumerationResponse: enumeration.raw,
|
|
105
|
+
});
|
|
106
|
+
if (resolved.status === 'unknown')
|
|
107
|
+
return suppressed('no-return-path', resolved.reason, resolved);
|
|
108
|
+
if (!resolved.returnPathProven)
|
|
109
|
+
return suppressed('no-return-path', 'The current mode is absent from the device catalog', resolved);
|
|
110
|
+
return {
|
|
111
|
+
status: 'available',
|
|
112
|
+
current: resolved.current,
|
|
113
|
+
enumerated: resolved.enumerated,
|
|
114
|
+
offerable: resolved.offerable.filter((mode) => !Object.is(mode, resolved.current)),
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
descriptor: descriptorFor(suppressed('provisioning-disabled', 'Capability has not been read for this device')),
|
|
119
|
+
describe: async (context) => descriptorFor(await capability(context)),
|
|
120
|
+
capability,
|
|
121
|
+
read: async (context) => result(context, { status: 'applied', value: await capability(context) }),
|
|
122
|
+
write: async (context, target) => {
|
|
123
|
+
const state = await capability(context);
|
|
124
|
+
if (state.status === 'suppressed')
|
|
125
|
+
return result(context, { status: 'refused', reason: state.reason });
|
|
126
|
+
if (!state.offerable.some((candidate) => Object.is(candidate, target)))
|
|
127
|
+
return result(context, { status: 'refused', reason: 'no-return-path' });
|
|
128
|
+
const fullCapability = {
|
|
129
|
+
status: 'available',
|
|
130
|
+
current: state.current,
|
|
131
|
+
enumerated: state.enumerated,
|
|
132
|
+
returnPathProven: true,
|
|
133
|
+
offerable: [state.current, ...state.offerable],
|
|
134
|
+
};
|
|
135
|
+
const outcome = await deps.transition(context, fullCapability, target);
|
|
136
|
+
if (outcome.status === 'refused')
|
|
137
|
+
return result(context, { status: 'refused', reason: 'blocked-by-state' });
|
|
138
|
+
if (outcome.status === 'failed')
|
|
139
|
+
return result(context, { status: 'failed', reason: outcome.reason });
|
|
140
|
+
return result(context, {
|
|
141
|
+
status: 'applied',
|
|
142
|
+
value: {
|
|
143
|
+
status: 'available',
|
|
144
|
+
current: target,
|
|
145
|
+
enumerated: state.enumerated,
|
|
146
|
+
offerable: state.enumerated.filter((mode) => !Object.is(mode, target)),
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type DecodedManagedObjects } from '../../backend/managed-objects.js';
|
|
2
|
+
import { type BandCertificationEntry } from '../../band/index.js';
|
|
3
|
+
import type { ProviderExecutionContext } from '../contracts.js';
|
|
4
|
+
import type { ModemManagerProviderSnapshot } from './types.js';
|
|
5
|
+
export declare function buildModemManagerSnapshot(tree: DecodedManagedObjects, context: ProviderExecutionContext, now: () => number, epoch: number, bandCertificationEntry: BandCertificationEntry | undefined): ModemManagerProviderSnapshot | undefined;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { MODEM_IFACE, MODEM_LOCATION_IFACE, MODEM3GPP_IFACE, MODEM3GPP_USSD_IFACE, SIM_IFACE, } from '../../backend/constants.js';
|
|
2
|
+
import { findInterface, pathsWithInterface, propValue, } from '../../backend/managed-objects.js';
|
|
3
|
+
import { decodeBandList } from '../../band/index.js';
|
|
4
|
+
import { MESSAGING_IFACE } from '../../capability/index.js';
|
|
5
|
+
import { decodeStateFailedReason, epochMillis, sourceEpoch, stableKeyFromPhysicalModemId, } from '../../domain/index.js';
|
|
6
|
+
import { readSimPresence } from '../../hardware/router-parsers.js';
|
|
7
|
+
import { normalizeModemManagerObservation } from '../../observations/index.js';
|
|
8
|
+
import { describeBandWriteCertification, readRadioModeTruth } from '../../radio/index.js';
|
|
9
|
+
const SIGNAL_IFACE = `${MODEM_IFACE}.Signal`;
|
|
10
|
+
function rawValue(value) {
|
|
11
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean')
|
|
12
|
+
return value;
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
const result = [];
|
|
15
|
+
for (const item of value) {
|
|
16
|
+
const decoded = rawValue(item);
|
|
17
|
+
if (decoded !== undefined)
|
|
18
|
+
result.push(decoded);
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function propsRecord(props) {
|
|
25
|
+
if (props === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
const record = {};
|
|
28
|
+
for (const [name, wrapped] of props) {
|
|
29
|
+
const decoded = rawValue(wrapped.value);
|
|
30
|
+
if (decoded !== undefined)
|
|
31
|
+
record[name] = decoded;
|
|
32
|
+
}
|
|
33
|
+
return record;
|
|
34
|
+
}
|
|
35
|
+
function tuple(value) {
|
|
36
|
+
if (!Array.isArray(value))
|
|
37
|
+
return [0, 0];
|
|
38
|
+
const allowed = value[0];
|
|
39
|
+
const preferred = value[1];
|
|
40
|
+
return [typeof allowed === 'number' ? allowed : 0, typeof preferred === 'number' ? preferred : 0];
|
|
41
|
+
}
|
|
42
|
+
function modePairs(value) {
|
|
43
|
+
if (!Array.isArray(value))
|
|
44
|
+
return [];
|
|
45
|
+
const result = [];
|
|
46
|
+
for (const candidate of value) {
|
|
47
|
+
const [allowed, preferred] = tuple(candidate);
|
|
48
|
+
if (allowed > 0)
|
|
49
|
+
result.push({ allowed, preferred });
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A `DbusValue` as the retention layer keeps it.
|
|
55
|
+
*
|
|
56
|
+
* `rawValue` already produces exactly this for a struct (an array of its members), so
|
|
57
|
+
* `SupportedModes` and `CurrentModes` reach the verbatim decoder in the same shape the
|
|
58
|
+
* diagnostics block retains — one representation, so the two cannot disagree.
|
|
59
|
+
*/
|
|
60
|
+
function structValue(value) {
|
|
61
|
+
return value === undefined ? undefined : rawValue(value);
|
|
62
|
+
}
|
|
63
|
+
function signalState(modem, signal) {
|
|
64
|
+
const quality = tuple(propValue(modem, 'SignalQuality'));
|
|
65
|
+
return {
|
|
66
|
+
...(quality[0] >= 0 ? { quality: quality[0] } : {}),
|
|
67
|
+
...(Array.isArray(propValue(modem, 'SignalQuality')) ? { recent: quality[1] !== 0 } : {}),
|
|
68
|
+
extendedAvailable: signal !== undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function simState(tree, modem) {
|
|
72
|
+
const activePath = propValue(modem, 'Sim');
|
|
73
|
+
const slots = propValue(modem, 'SimSlots');
|
|
74
|
+
const paths = Array.isArray(slots)
|
|
75
|
+
? slots.filter((value) => typeof value === 'string' && value !== '/')
|
|
76
|
+
: [];
|
|
77
|
+
const active = typeof activePath === 'string' ? findInterface(tree, activePath, SIM_IFACE) : undefined;
|
|
78
|
+
const lockRequired = propValue(modem, 'UnlockRequired');
|
|
79
|
+
const rawFailedReason = propValue(modem, 'StateFailedReason');
|
|
80
|
+
const failedReason = typeof rawFailedReason === 'number'
|
|
81
|
+
? decodeStateFailedReason(rawFailedReason)
|
|
82
|
+
: typeof rawFailedReason === 'string'
|
|
83
|
+
? rawFailedReason
|
|
84
|
+
: undefined;
|
|
85
|
+
const primarySlot = propValue(modem, 'PrimarySimSlot');
|
|
86
|
+
const simType = propValue(active, 'SimType');
|
|
87
|
+
const esimStatus = propValue(active, 'EsimStatus');
|
|
88
|
+
const reading = readSimPresence({
|
|
89
|
+
...(typeof activePath === 'string' ? { sim: activePath } : {}),
|
|
90
|
+
...(paths.length > 0 ? { simSlots: paths } : {}),
|
|
91
|
+
...(failedReason === undefined ? {} : { failedReason }),
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
// POSITIVE evidence only: an exported SIM object path proves a SIM. Its ABSENCE
|
|
95
|
+
// proves nothing — `presence` below is the answer to "is there a SIM", and it
|
|
96
|
+
// says `unknown` unless the modem stated `sim-missing` itself.
|
|
97
|
+
present: typeof activePath === 'string' && activePath !== '/',
|
|
98
|
+
presence: reading.presence,
|
|
99
|
+
presenceEvidence: reading.evidence,
|
|
100
|
+
slotCount: paths.length,
|
|
101
|
+
primarySlot: typeof primarySlot === 'number' ? primarySlot : 0,
|
|
102
|
+
...(typeof lockRequired === 'number' ? { lockRequired } : {}),
|
|
103
|
+
...(typeof simType === 'number' ? { simType } : {}),
|
|
104
|
+
...(typeof esimStatus === 'number' ? { esimStatus } : {}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function radioPower(value) {
|
|
108
|
+
switch (value) {
|
|
109
|
+
case 1:
|
|
110
|
+
return 'off';
|
|
111
|
+
case 2:
|
|
112
|
+
return 'low';
|
|
113
|
+
case 3:
|
|
114
|
+
return 'on';
|
|
115
|
+
default:
|
|
116
|
+
return 'unknown';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function hasProperty(props, name) {
|
|
120
|
+
return props.some(([property]) => property === name);
|
|
121
|
+
}
|
|
122
|
+
function findModemPath(tree, context) {
|
|
123
|
+
const [kind, ...parts] = String(context.physicalModemId).split(':');
|
|
124
|
+
const expected = parts.join(':');
|
|
125
|
+
for (const path of pathsWithInterface(tree, MODEM_IFACE)) {
|
|
126
|
+
const modem = findInterface(tree, path, MODEM_IFACE);
|
|
127
|
+
const candidates = kind === 'serial'
|
|
128
|
+
? [propValue(modem, 'DeviceIdentifier')]
|
|
129
|
+
: [propValue(modem, 'Device'), propValue(modem, 'Physdev')];
|
|
130
|
+
if (candidates.some((candidate) => candidate === expected))
|
|
131
|
+
return path;
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
export function buildModemManagerSnapshot(tree, context, now, epoch, bandCertificationEntry) {
|
|
136
|
+
const modemPath = findModemPath(tree, context);
|
|
137
|
+
if (modemPath === undefined)
|
|
138
|
+
return undefined;
|
|
139
|
+
const modem = findInterface(tree, modemPath, MODEM_IFACE);
|
|
140
|
+
if (modem === undefined)
|
|
141
|
+
return undefined;
|
|
142
|
+
const modem3gpp = findInterface(tree, modemPath, MODEM3GPP_IFACE);
|
|
143
|
+
const signal = findInterface(tree, modemPath, SIGNAL_IFACE);
|
|
144
|
+
const activePath = propValue(modem, 'Sim');
|
|
145
|
+
const sim = typeof activePath === 'string' ? findInterface(tree, activePath, SIM_IFACE) : undefined;
|
|
146
|
+
const interfaces = tree.find(([path]) => path === modemPath)?.[1] ?? [];
|
|
147
|
+
const interfaceNames = new Set(interfaces.map(([name]) => name));
|
|
148
|
+
const slots = propValue(modem, 'SimSlots');
|
|
149
|
+
const bandCertification = describeBandWriteCertification({
|
|
150
|
+
entry: bandCertificationEntry,
|
|
151
|
+
supported: decodeBandList(propValue(modem, 'SupportedBands')),
|
|
152
|
+
});
|
|
153
|
+
const capabilities = {
|
|
154
|
+
modeRead: hasProperty(modem, 'CurrentModes'),
|
|
155
|
+
modeWrite: hasProperty(modem, 'CurrentModes'),
|
|
156
|
+
bandRead: hasProperty(modem, 'SupportedBands'),
|
|
157
|
+
bandWrite: hasProperty(modem, 'SupportedBands') &&
|
|
158
|
+
bandCertification.satisfied &&
|
|
159
|
+
bandCertification.offerable.length > 0,
|
|
160
|
+
signalRead: hasProperty(modem, 'SignalQuality') || signal !== undefined,
|
|
161
|
+
simRead: hasProperty(modem, 'Sim') || hasProperty(modem, 'SimSlots'),
|
|
162
|
+
multiSim: Array.isArray(slots) && slots.filter((entry) => entry !== '/').length > 1,
|
|
163
|
+
location: interfaceNames.has(MODEM_LOCATION_IFACE),
|
|
164
|
+
sms: interfaceNames.has(MESSAGING_IFACE),
|
|
165
|
+
ussd: interfaceNames.has(MODEM3GPP_USSD_IFACE),
|
|
166
|
+
powerRead: hasProperty(modem, 'PowerState'),
|
|
167
|
+
};
|
|
168
|
+
const [allowed, preferred] = tuple(propValue(modem, 'CurrentModes'));
|
|
169
|
+
const modeTruth = readRadioModeTruth({
|
|
170
|
+
currentModes: structValue(propValue(modem, 'CurrentModes')),
|
|
171
|
+
supportedModes: structValue(propValue(modem, 'SupportedModes')),
|
|
172
|
+
});
|
|
173
|
+
const normalizationContext = {
|
|
174
|
+
stableKey: stableKeyFromPhysicalModemId(context.physicalModemId),
|
|
175
|
+
generation: context.generation,
|
|
176
|
+
sourceEpoch: sourceEpoch(epoch),
|
|
177
|
+
observedAt: epochMillis(now()),
|
|
178
|
+
};
|
|
179
|
+
// The struct properties are handed to normalization VERBATIM — `CurrentModes` as its
|
|
180
|
+
// `(uu)` pair, `SignalQuality` as its `(ub)` pair. Flattening them here (which this
|
|
181
|
+
// did) kept the first member and dropped the preferred mode and the recency flag
|
|
182
|
+
// before the diagnostics block ever saw them, which is a drop no downstream layer
|
|
183
|
+
// can undo. The normalizer reads either shape.
|
|
184
|
+
const modemRaw = propsRecord(modem) ?? {};
|
|
185
|
+
return {
|
|
186
|
+
modemPath,
|
|
187
|
+
capabilities,
|
|
188
|
+
bandCertification,
|
|
189
|
+
radio: {
|
|
190
|
+
current: { allowed, preferred },
|
|
191
|
+
supported: modePairs(propValue(modem, 'SupportedModes')),
|
|
192
|
+
truth: modeTruth,
|
|
193
|
+
},
|
|
194
|
+
signal: signalState(modem, signal),
|
|
195
|
+
sim: simState(tree, modem),
|
|
196
|
+
power: radioPower(propValue(modem, 'PowerState')),
|
|
197
|
+
observation: normalizeModemManagerObservation({
|
|
198
|
+
modem: modemRaw,
|
|
199
|
+
...(modem3gpp === undefined ? {} : { modem3gpp: propsRecord(modem3gpp) ?? {} }),
|
|
200
|
+
...(sim === undefined ? {} : { sim: propsRecord(sim) ?? {} }),
|
|
201
|
+
...(signal === undefined ? {} : { signal: propsRecord(signal) ?? {} }),
|
|
202
|
+
}, normalizationContext),
|
|
203
|
+
};
|
|
204
|
+
}
|