@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,23 @@
|
|
|
1
|
+
import type { AuthenticatedProfileResult, ProviderMatchRequest } from '../contracts.js';
|
|
2
|
+
import { type ZteOptions, type ZteProfile } from './provider.js';
|
|
3
|
+
import type { ZteHttpResponse } from './transport.js';
|
|
4
|
+
type ZteEvidence = {
|
|
5
|
+
readonly record: Readonly<Record<string, string | number>>;
|
|
6
|
+
readonly profile: ZteProfile | undefined;
|
|
7
|
+
};
|
|
8
|
+
export declare function parseZteRecord(body: string): Readonly<Record<string, string | number>> | undefined;
|
|
9
|
+
export declare class ZteSessionRuntime {
|
|
10
|
+
#private;
|
|
11
|
+
protected readonly options: ZteOptions;
|
|
12
|
+
constructor(options: ZteOptions);
|
|
13
|
+
authenticateProfile(request: ProviderMatchRequest, candidates: readonly string[]): Promise<AuthenticatedProfileResult>;
|
|
14
|
+
protected probeEvidence(request: ProviderMatchRequest): Promise<ZteEvidence | undefined>;
|
|
15
|
+
protected sessionCookie(request: ProviderMatchRequest): string | undefined;
|
|
16
|
+
protected get(cmd: string, cookie?: string, multiData?: boolean): Promise<ZteHttpResponse>;
|
|
17
|
+
private login;
|
|
18
|
+
private loginSalted;
|
|
19
|
+
private sessionKey;
|
|
20
|
+
private post;
|
|
21
|
+
private request;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { ZTE_EVIDENCE_CMD, ZTE_PATHS, ZTE_UNKNOWN_PROFILE, zteProfileById, zteProfilesForFirmware, } from './provider.js';
|
|
4
|
+
const flatRecordSchema = z.record(z.string(), z.union([z.string(), z.number()]));
|
|
5
|
+
export function parseZteRecord(body) {
|
|
6
|
+
const result = z
|
|
7
|
+
.string()
|
|
8
|
+
.transform((value, context) => {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(value);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (!(error instanceof SyntaxError))
|
|
14
|
+
throw error;
|
|
15
|
+
context.addIssue({ code: 'custom', message: 'invalid JSON' });
|
|
16
|
+
return z.NEVER;
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
.pipe(flatRecordSchema)
|
|
20
|
+
.safeParse(body);
|
|
21
|
+
return result.success ? result.data : undefined;
|
|
22
|
+
}
|
|
23
|
+
function stokCookie(response) {
|
|
24
|
+
const expected = 'set-cookie';
|
|
25
|
+
const header = Object.entries(response.headers ?? {}).find(([key]) => key.toLowerCase() === expected)?.[1];
|
|
26
|
+
const cookie = header?.split(';', 1)[0]?.trim();
|
|
27
|
+
return cookie?.startsWith('stok=') ? cookie : undefined;
|
|
28
|
+
}
|
|
29
|
+
function sha256(value) {
|
|
30
|
+
return createHash('sha256').update(value).digest('hex').toUpperCase();
|
|
31
|
+
}
|
|
32
|
+
function evidenceNumber(value) {
|
|
33
|
+
if (typeof value === 'string' && value.trim() === '')
|
|
34
|
+
return undefined;
|
|
35
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
36
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : undefined;
|
|
37
|
+
}
|
|
38
|
+
function profileFromEvidence(firmware, record) {
|
|
39
|
+
const versionEvidence = `${record.wa_inner_version ?? ''} ${record.cr_version ?? ''}`.toUpperCase();
|
|
40
|
+
const family = versionEvidence.includes('MF266')
|
|
41
|
+
? 'MF266'
|
|
42
|
+
: versionEvidence.includes('MF79U')
|
|
43
|
+
? 'MF79U'
|
|
44
|
+
: firmware;
|
|
45
|
+
const hasLd = typeof record.LD === 'string' && record.LD.length > 0;
|
|
46
|
+
const profileId = family === 'MF266'
|
|
47
|
+
? hasLd
|
|
48
|
+
? 'mf266-salted'
|
|
49
|
+
: undefined
|
|
50
|
+
: family === 'MF79U'
|
|
51
|
+
? hasLd
|
|
52
|
+
? 'mf79u-ld-salted'
|
|
53
|
+
: 'mf79u-legacy'
|
|
54
|
+
: undefined;
|
|
55
|
+
return zteProfilesForFirmware(family).find((profile) => profile.id === profileId);
|
|
56
|
+
}
|
|
57
|
+
function classifyLogin(response) {
|
|
58
|
+
const result = parseZteRecord(response.body)?.result;
|
|
59
|
+
if (response.status !== 200 || result === '1') {
|
|
60
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
61
|
+
}
|
|
62
|
+
if (result === '3')
|
|
63
|
+
return { status: 'refused', detail: 'auth-rejection' };
|
|
64
|
+
const cookie = stokCookie(response);
|
|
65
|
+
return result === '0' && cookie !== undefined
|
|
66
|
+
? { status: 'accepted', cookie }
|
|
67
|
+
: { status: 'refused', detail: 'protocol-mismatch' };
|
|
68
|
+
}
|
|
69
|
+
export class ZteSessionRuntime {
|
|
70
|
+
options;
|
|
71
|
+
#sessions = new Map();
|
|
72
|
+
#evidence = new Map();
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.options = options;
|
|
75
|
+
}
|
|
76
|
+
async authenticateProfile(request, candidates) {
|
|
77
|
+
const candidate = candidates.length === 1 ? candidates[0] : undefined;
|
|
78
|
+
if (candidate === ZTE_UNKNOWN_PROFILE) {
|
|
79
|
+
return { status: 'matched', profile: ZTE_UNKNOWN_PROFILE, detail: 'read-only-fingerprint' };
|
|
80
|
+
}
|
|
81
|
+
const profile = zteProfileById(candidate ?? '');
|
|
82
|
+
if (profile === undefined) {
|
|
83
|
+
return { status: 'refused', detail: 'profile-mismatch' };
|
|
84
|
+
}
|
|
85
|
+
const evidence = this.#evidence.get(this.sessionKey(request)) ?? (await this.probeEvidence(request));
|
|
86
|
+
if (evidence === undefined)
|
|
87
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
88
|
+
const remainingAttempts = evidenceNumber(evidence.record.psw_fail_num_str);
|
|
89
|
+
const lockTime = evidenceNumber(evidence.record.login_lock_time);
|
|
90
|
+
if (remainingAttempts === undefined || lockTime === undefined) {
|
|
91
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
92
|
+
}
|
|
93
|
+
if (lockTime > 0 || remainingAttempts === 0) {
|
|
94
|
+
return { status: 'refused', detail: 'lockout' };
|
|
95
|
+
}
|
|
96
|
+
if (evidence.profile?.id !== profile.id) {
|
|
97
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
98
|
+
}
|
|
99
|
+
switch (profile.algorithm) {
|
|
100
|
+
case 'legacy-base64':
|
|
101
|
+
return this.login(request, profile, Buffer.from(this.options.credentials.password).toString('base64'));
|
|
102
|
+
case 'login-salted-sha256': {
|
|
103
|
+
const ld = evidence.record.LD;
|
|
104
|
+
if (typeof ld !== 'string')
|
|
105
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
106
|
+
return this.login(request, profile, sha256(`${sha256(this.options.credentials.password)}${ld}`));
|
|
107
|
+
}
|
|
108
|
+
case 'multi-user-salted-sha256':
|
|
109
|
+
return this.loginSalted(request, profile, evidence.record);
|
|
110
|
+
default: {
|
|
111
|
+
const exhaustive = profile.algorithm;
|
|
112
|
+
return exhaustive;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async probeEvidence(request) {
|
|
117
|
+
const response = await this.get(ZTE_EVIDENCE_CMD, undefined, true);
|
|
118
|
+
const record = response.status === 200 ? parseZteRecord(response.body) : undefined;
|
|
119
|
+
if (record === undefined)
|
|
120
|
+
return undefined;
|
|
121
|
+
const evidence = { record, profile: profileFromEvidence(request.firmware, record) };
|
|
122
|
+
this.#evidence.set(this.sessionKey(request), evidence);
|
|
123
|
+
return evidence;
|
|
124
|
+
}
|
|
125
|
+
sessionCookie(request) {
|
|
126
|
+
return this.#sessions.get(this.sessionKey(request))?.cookie;
|
|
127
|
+
}
|
|
128
|
+
get(cmd, cookie, multiData = false) {
|
|
129
|
+
const query = new URLSearchParams({ isTest: 'false', cmd });
|
|
130
|
+
if (multiData)
|
|
131
|
+
query.set('multi_data', '1');
|
|
132
|
+
return this.request('GET', `${ZTE_PATHS.get}?${query.toString()}`, undefined, cookie);
|
|
133
|
+
}
|
|
134
|
+
async login(request, profile, password) {
|
|
135
|
+
const response = await this.post(new URLSearchParams({
|
|
136
|
+
goformId: 'LOGIN',
|
|
137
|
+
isTest: 'false',
|
|
138
|
+
password,
|
|
139
|
+
}).toString());
|
|
140
|
+
const result = classifyLogin(response);
|
|
141
|
+
if (result.status === 'refused')
|
|
142
|
+
return result;
|
|
143
|
+
this.#sessions.set(this.sessionKey(request), { cookie: result.cookie });
|
|
144
|
+
return { status: 'matched', profile: profile.id, detail: 'login-ok' };
|
|
145
|
+
}
|
|
146
|
+
async loginSalted(request, profile, evidence) {
|
|
147
|
+
const ld = evidence.LD;
|
|
148
|
+
if (typeof ld !== 'string') {
|
|
149
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
150
|
+
}
|
|
151
|
+
const login = await this.post(new URLSearchParams({
|
|
152
|
+
goformId: 'LOGIN_MULTI_USER',
|
|
153
|
+
isTest: 'false',
|
|
154
|
+
password: sha256(`${sha256(this.options.credentials.password)}${ld}`),
|
|
155
|
+
IP: 'localhost',
|
|
156
|
+
user: this.options.credentials.username,
|
|
157
|
+
}).toString());
|
|
158
|
+
const result = classifyLogin(login);
|
|
159
|
+
if (result.status === 'refused')
|
|
160
|
+
return result;
|
|
161
|
+
const rd = parseZteRecord((await this.get('RD', result.cookie)).body)?.RD;
|
|
162
|
+
const waVersion = evidence.wa_inner_version;
|
|
163
|
+
const crVersion = evidence.cr_version;
|
|
164
|
+
if (typeof waVersion !== 'string' || typeof crVersion !== 'string' || typeof rd !== 'string') {
|
|
165
|
+
return { status: 'refused', detail: 'protocol-mismatch' };
|
|
166
|
+
}
|
|
167
|
+
this.#sessions.set(this.sessionKey(request), {
|
|
168
|
+
cookie: result.cookie,
|
|
169
|
+
ad: sha256(`${sha256(`${waVersion}${crVersion}`)}${rd}`),
|
|
170
|
+
});
|
|
171
|
+
return { status: 'matched', profile: profile.id, detail: 'login-ok' };
|
|
172
|
+
}
|
|
173
|
+
sessionKey(request) {
|
|
174
|
+
return `${request.physicalModemId}:${request.generation}`;
|
|
175
|
+
}
|
|
176
|
+
post(body) {
|
|
177
|
+
return this.request('POST', ZTE_PATHS.set, body);
|
|
178
|
+
}
|
|
179
|
+
request(method, path, body, cookie) {
|
|
180
|
+
const headers = [
|
|
181
|
+
...(method === 'POST'
|
|
182
|
+
? ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8']
|
|
183
|
+
: []),
|
|
184
|
+
...(cookie === undefined ? [] : [`Cookie: ${cookie}`]),
|
|
185
|
+
`Origin: ${this.options.adminUrl}`,
|
|
186
|
+
`Referer: ${this.options.adminUrl}/index.html`,
|
|
187
|
+
];
|
|
188
|
+
return this.options.transport.request({
|
|
189
|
+
method,
|
|
190
|
+
url: `${this.options.adminUrl}${path}`,
|
|
191
|
+
...(body === undefined ? {} : { body }),
|
|
192
|
+
headers,
|
|
193
|
+
interfaceName: this.options.interfaceName,
|
|
194
|
+
redirect: 'error',
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ZteHttpRequest = {
|
|
2
|
+
readonly method: 'GET' | 'POST';
|
|
3
|
+
readonly url: string;
|
|
4
|
+
readonly body?: string;
|
|
5
|
+
readonly headers: readonly string[];
|
|
6
|
+
readonly interfaceName: string;
|
|
7
|
+
readonly redirect: 'error';
|
|
8
|
+
};
|
|
9
|
+
export type ZteHttpResponse = {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
readonly body: string;
|
|
12
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
13
|
+
};
|
|
14
|
+
export interface ZteTransport {
|
|
15
|
+
request(request: ZteHttpRequest): Promise<ZteHttpResponse>;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type BandCertificationEntry, type BandName } from '../band/index.js';
|
|
2
|
+
import { type OperationDescriptor } from '../domain/index.js';
|
|
3
|
+
import type { ModemBands } from '../ports/index.js';
|
|
4
|
+
export declare const BAND_WRITE_OPERATION_ID = "modemmanager.bands";
|
|
5
|
+
/** The refusal reasons a band write may carry. Certification is the first gate. */
|
|
6
|
+
export declare const BAND_WRITE_REFUSAL = "band-certification-required";
|
|
7
|
+
export declare const BAND_READ_REFUSAL = "band-read-unsupported";
|
|
8
|
+
export declare const BAND_NONE_OFFERABLE_REFUSAL = "no-offerable-certified-bands";
|
|
9
|
+
/**
|
|
10
|
+
* The band-lock certification decision for one device, as a descriptor consumer sees it.
|
|
11
|
+
*
|
|
12
|
+
* `required` is `true` unconditionally and is typed as the literal, so no code path can
|
|
13
|
+
* produce a band-write decision that does not require certification. This is the one
|
|
14
|
+
* capability module documented as STRICTER than `support-claim.ts`'s `capable` floor.
|
|
15
|
+
*/
|
|
16
|
+
export type BandWriteCertification = {
|
|
17
|
+
readonly required: true;
|
|
18
|
+
readonly satisfied: boolean;
|
|
19
|
+
readonly reason: 'band-certification-proven' | typeof BAND_WRITE_REFUSAL;
|
|
20
|
+
/** What the catalog proves is settable, intersected with what the modem advertises. */
|
|
21
|
+
readonly offerable: readonly BandName[];
|
|
22
|
+
};
|
|
23
|
+
export declare function describeBandWriteCertification(input: {
|
|
24
|
+
readonly entry: BandCertificationEntry | undefined;
|
|
25
|
+
readonly supported: readonly BandName[];
|
|
26
|
+
}): BandWriteCertification;
|
|
27
|
+
export type BandWriteDescriptorInput = {
|
|
28
|
+
readonly provider: string;
|
|
29
|
+
readonly profile: string;
|
|
30
|
+
readonly certification: BandWriteCertification;
|
|
31
|
+
readonly readSupported: boolean;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Whether a band readback confirms the write.
|
|
35
|
+
*
|
|
36
|
+
* A NARROWING lock must match exactly — a superset is a different lock from the one
|
|
37
|
+
* that was asked for. The reset (`['any']`) is the exception ModemManager forces:
|
|
38
|
+
* releasing a lock is `SetCurrentBands([ANY])`, and a modem afterwards reports either
|
|
39
|
+
* `any` or its whole supported set, both of which mean "no lock is in force".
|
|
40
|
+
*/
|
|
41
|
+
export declare function bandWriteReadbackMatches(requested: readonly BandName[], observed: ModemBands): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The live band-write descriptor.
|
|
44
|
+
*
|
|
45
|
+
* `mutationImpact: 'disruptive'` because `SetCurrentBands` re-registers the radio and
|
|
46
|
+
* drops the bearer underneath NetworkManager; `readback` is REQUIRED because an
|
|
47
|
+
* accepted-but-ignored band write is the failure mode the catalog's own `readback`
|
|
48
|
+
* proof exists to catch, and it looks like success from the call site alone.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildBandWriteDescriptor(input: BandWriteDescriptorInput): OperationDescriptor<readonly BandName[], ModemBands>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// The band-write descriptor — the certification gate, expressed as an operation contract.
|
|
2
|
+
//
|
|
3
|
+
// It ADDS NOTHING to `band/certification.ts`. That module already owns the four-proof
|
|
4
|
+
// per-SKU catalog, the fail-closed lookup, and the `offerableBands` narrowing, and it
|
|
5
|
+
// is the only place a SKU may be declared certified. What was missing was the other
|
|
6
|
+
// end of the wire: a band write's OPERATION DESCRIPTOR did not say that it is
|
|
7
|
+
// disruptive-with-a-certification-requirement, so the gate lived only inside the
|
|
8
|
+
// provider's capability flag and a consumer reading the descriptor could not see it.
|
|
9
|
+
//
|
|
10
|
+
// TWO INDEPENDENT FENCES, deliberately. `availability: refused` is what a consumer
|
|
11
|
+
// reads to decide whether to offer the control at all; the provider's own
|
|
12
|
+
// `bandWrite` capability check is what refuses the call if one is made anyway. A gate
|
|
13
|
+
// that exists only in the descriptor is advisory, and a gate that exists only in the
|
|
14
|
+
// provider is invisible — a band lock can take a working uplink off the air, so it
|
|
15
|
+
// gets both.
|
|
16
|
+
import { offerableBands } from '../band/index.js';
|
|
17
|
+
import { defineOperationDescriptor } from '../domain/index.js';
|
|
18
|
+
export const BAND_WRITE_OPERATION_ID = 'modemmanager.bands';
|
|
19
|
+
/** The refusal reasons a band write may carry. Certification is the first gate. */
|
|
20
|
+
export const BAND_WRITE_REFUSAL = 'band-certification-required';
|
|
21
|
+
export const BAND_READ_REFUSAL = 'band-read-unsupported';
|
|
22
|
+
export const BAND_NONE_OFFERABLE_REFUSAL = 'no-offerable-certified-bands';
|
|
23
|
+
export function describeBandWriteCertification(input) {
|
|
24
|
+
const offerable = offerableBands(input.entry, input.supported);
|
|
25
|
+
return input.entry === undefined
|
|
26
|
+
? { required: true, satisfied: false, reason: BAND_WRITE_REFUSAL, offerable }
|
|
27
|
+
: { required: true, satisfied: true, reason: 'band-certification-proven', offerable };
|
|
28
|
+
}
|
|
29
|
+
function sameBandSet(left, right) {
|
|
30
|
+
if (left.length !== right.length)
|
|
31
|
+
return false;
|
|
32
|
+
const sorted = [...right].sort();
|
|
33
|
+
return [...left].sort().every((band, index) => band === sorted[index]);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether a band readback confirms the write.
|
|
37
|
+
*
|
|
38
|
+
* A NARROWING lock must match exactly — a superset is a different lock from the one
|
|
39
|
+
* that was asked for. The reset (`['any']`) is the exception ModemManager forces:
|
|
40
|
+
* releasing a lock is `SetCurrentBands([ANY])`, and a modem afterwards reports either
|
|
41
|
+
* `any` or its whole supported set, both of which mean "no lock is in force".
|
|
42
|
+
*/
|
|
43
|
+
export function bandWriteReadbackMatches(requested, observed) {
|
|
44
|
+
if (requested.length === 1 && requested[0] === 'any') {
|
|
45
|
+
return ((observed.current.length === 1 && observed.current[0] === 'any') ||
|
|
46
|
+
sameBandSet(observed.current, observed.supported));
|
|
47
|
+
}
|
|
48
|
+
return sameBandSet(requested, observed.current);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The live band-write descriptor.
|
|
52
|
+
*
|
|
53
|
+
* `mutationImpact: 'disruptive'` because `SetCurrentBands` re-registers the radio and
|
|
54
|
+
* drops the bearer underneath NetworkManager; `readback` is REQUIRED because an
|
|
55
|
+
* accepted-but-ignored band write is the failure mode the catalog's own `readback`
|
|
56
|
+
* proof exists to catch, and it looks like success from the call site alone.
|
|
57
|
+
*/
|
|
58
|
+
export function buildBandWriteDescriptor(input) {
|
|
59
|
+
const refusal = !input.certification.satisfied
|
|
60
|
+
? BAND_WRITE_REFUSAL
|
|
61
|
+
: input.certification.offerable.length === 0
|
|
62
|
+
? BAND_NONE_OFFERABLE_REFUSAL
|
|
63
|
+
: undefined;
|
|
64
|
+
return defineOperationDescriptor({
|
|
65
|
+
id: BAND_WRITE_OPERATION_ID,
|
|
66
|
+
support: {
|
|
67
|
+
read: input.readSupported
|
|
68
|
+
? { supported: true }
|
|
69
|
+
: { supported: false, reason: BAND_READ_REFUSAL },
|
|
70
|
+
write: input.certification.satisfied
|
|
71
|
+
? { supported: true }
|
|
72
|
+
: { supported: false, reason: BAND_WRITE_REFUSAL },
|
|
73
|
+
},
|
|
74
|
+
authority: 'provider',
|
|
75
|
+
provider: input.provider,
|
|
76
|
+
constraints: { kind: 'allowed-values', values: [input.certification.offerable] },
|
|
77
|
+
livePreconditions: ['modem-present', 'runtime-interface-present', 'band-certification-present'],
|
|
78
|
+
availability: refusal === undefined ? { state: 'available' } : { state: 'refused', reason: refusal },
|
|
79
|
+
mutationImpact: 'disruptive',
|
|
80
|
+
retryClass: 'never',
|
|
81
|
+
readback: {
|
|
82
|
+
required: true,
|
|
83
|
+
reason: 'band-write-readback',
|
|
84
|
+
matches: bandWriteReadbackMatches,
|
|
85
|
+
},
|
|
86
|
+
rollback: { required: false },
|
|
87
|
+
journal: { required: true, reason: 'disruptive-radio-write' },
|
|
88
|
+
admission: { required: true, reason: 'provider-mutation' },
|
|
89
|
+
evidence: { profiles: [input.profile], firmware: [] },
|
|
90
|
+
confidence: 'high',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Radio capability TRUTH: the modem's own mode catalog and band-write gate, verbatim.
|
|
2
|
+
//
|
|
3
|
+
// It sits beside `src/band/` (the band vocabulary and per-SKU certification catalog)
|
|
4
|
+
// rather than inside it, because a mode combination is not a band and the two have
|
|
5
|
+
// different safety models — a mode change is disruptive-but-reversible, a band lock
|
|
6
|
+
// can strand a radio where nothing registers. Reachable through the package ROOT
|
|
7
|
+
// entry, deliberately NOT a new package subpath (the todo 17/18/23 precedent).
|
|
8
|
+
export * from './band-truth.js';
|
|
9
|
+
export * from './mode-combinations.js';
|
|
10
|
+
export * from './mode-truth.js';
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** A mode as every operator-facing surface spells it. Opaque; compare by equality. */
|
|
2
|
+
export type ModeName = string;
|
|
3
|
+
/**
|
|
4
|
+
* `MM_MODEM_MODE_NONE` (0) — the modem expresses no preference within its allowed set.
|
|
5
|
+
* A legal, load-bearing value; never a stand-in for "not reported".
|
|
6
|
+
*/
|
|
7
|
+
export declare const MODE_NONE = "none";
|
|
8
|
+
/** `MM_MODEM_MODE_ANY` (0xFFFFFFFF) — every mode the modem has. */
|
|
9
|
+
export declare const MODE_ANY = "any";
|
|
10
|
+
/** Decode one `MMModemMode` bit. Total: an unnamed bit round-trips. */
|
|
11
|
+
export declare function modeName(bit: number): ModeName;
|
|
12
|
+
/** Encode one mode name. `undefined` for a name this build cannot place. */
|
|
13
|
+
export declare function modeValue(name: ModeName): number | undefined;
|
|
14
|
+
/** True when this build recognises the name (a `mode-bit-<n>` passthrough does not). */
|
|
15
|
+
export declare function isNamedMode(name: ModeName): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Split a mask into its set bits, named where this build can and passed through where
|
|
18
|
+
* it cannot. A zero mask is the EMPTY set — the caller decides whether that reads as
|
|
19
|
+
* `none` (a preference) or as an anomaly (an allowed set nothing can be chosen from).
|
|
20
|
+
*/
|
|
21
|
+
export declare function modeNames(mask: number): readonly ModeName[];
|
|
22
|
+
/** Encode a set of mode names into one mask. Fails closed on an unplaceable name. */
|
|
23
|
+
export declare function encodeModeNames(names: readonly ModeName[]): {
|
|
24
|
+
readonly ok: true;
|
|
25
|
+
readonly mask: number;
|
|
26
|
+
} | {
|
|
27
|
+
readonly ok: false;
|
|
28
|
+
readonly unknown: ModeName;
|
|
29
|
+
};
|
|
30
|
+
/** Why a combination could not be fully placed. Never a reason to hide it. */
|
|
31
|
+
export declare const MODE_COMBINATION_ANOMALIES: readonly [
|
|
32
|
+
/** The allowed mask carries a bit this build does not name. */
|
|
33
|
+
'unnamed-allowed-bit',
|
|
34
|
+
/** The preferred mask carries a bit this build does not name. */
|
|
35
|
+
'unnamed-preferred-bit',
|
|
36
|
+
/** The preferred mode is not a member of the allowed set. */
|
|
37
|
+
'preferred-not-in-allowed',
|
|
38
|
+
/** The preferred mask names more than one mode; MM's contract is at most one. */
|
|
39
|
+
'preferred-not-singular',
|
|
40
|
+
/** The allowed mask is zero — nothing can be selected from this combination. */
|
|
41
|
+
'empty-allowed'];
|
|
42
|
+
export type ModeCombinationAnomaly = (typeof MODE_COMBINATION_ANOMALIES)[number];
|
|
43
|
+
export type ModeCombinationClassification = 'named' | 'unknown-combination';
|
|
44
|
+
/**
|
|
45
|
+
* One `(allowed, preferred)` pair, decoded without loss.
|
|
46
|
+
*
|
|
47
|
+
* The masks are retained ALONGSIDE the names so a consumer can always reproduce the
|
|
48
|
+
* exact bytes the modem reported, whatever this build managed to name.
|
|
49
|
+
*/
|
|
50
|
+
export type ModeCombination = {
|
|
51
|
+
readonly allowedMask: number;
|
|
52
|
+
readonly allowed: readonly ModeName[];
|
|
53
|
+
readonly preferredMask: number;
|
|
54
|
+
/** `none` when the modem stated no preference — verbatim, never a substitute. */
|
|
55
|
+
readonly preferred: ModeName;
|
|
56
|
+
readonly classification: ModeCombinationClassification;
|
|
57
|
+
readonly anomalies: readonly ModeCombinationAnomaly[];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* A `SupportedModes` catalog: everything decoded, plus everything that could not be.
|
|
61
|
+
*
|
|
62
|
+
* `undecodable` exists so the no-drop property is structural rather than a promise —
|
|
63
|
+
* `combinations.length + undecodable.length` is the member count the provider sent.
|
|
64
|
+
*/
|
|
65
|
+
export type ModeCombinationSet = {
|
|
66
|
+
readonly combinations: readonly ModeCombination[];
|
|
67
|
+
/** Members that were not a `(uu)` pair, retained exactly as the provider sent them. */
|
|
68
|
+
readonly undecodable: readonly unknown[];
|
|
69
|
+
};
|
|
70
|
+
/** Build a combination from two raw masks, recording every anomaly it carries. */
|
|
71
|
+
export declare function modeCombination(allowedMask: number, preferredMask: number): ModeCombination;
|
|
72
|
+
/** True when the modem stated no preference within this combination's allowed set. */
|
|
73
|
+
export declare function statesNoPreference(combination: ModeCombination): boolean;
|
|
74
|
+
/** Decode one `CurrentModes` `(uu)`. `undefined` only when the value is not a pair. */
|
|
75
|
+
export declare function decodeModeCombination(value: unknown): ModeCombination | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Decode a `SupportedModes` `a(uu)`.
|
|
78
|
+
*
|
|
79
|
+
* Nothing is dropped: a member that is not a pair lands in `undecodable`, and a pair
|
|
80
|
+
* this build cannot fully name lands in `combinations` classified
|
|
81
|
+
* `unknown-combination`. A non-array value is an empty catalog, not an error — a modem
|
|
82
|
+
* that advertises no mode control is a real reading.
|
|
83
|
+
*/
|
|
84
|
+
export declare function decodeSupportedModeCombinations(value: unknown): ModeCombinationSet;
|
|
85
|
+
/** True when any advertised combination carries an anomaly this build could not place. */
|
|
86
|
+
export declare function hasUnknownCombination(set: ModeCombinationSet): boolean;
|
|
87
|
+
/** Whether a mask names a mode this build recognises across every set bit. */
|
|
88
|
+
export declare function isFullyNamedMask(mask: number): boolean;
|