@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,40 @@
|
|
|
1
|
+
/** The current on-disk schema version. Bump when the persisted shape changes. */
|
|
2
|
+
export declare const FCC_UNLOCK_SCHEMA_VERSION = 1;
|
|
3
|
+
/** The pinned location of the policy of record. `/data` survives a slot swap. */
|
|
4
|
+
export declare const FCC_UNLOCK_POLICY_PATH = "/data/ceralive/fcc-unlock-policy.json";
|
|
5
|
+
/**
|
|
6
|
+
* The persisted document.
|
|
7
|
+
*
|
|
8
|
+
* `unlock` is a TOTAL map from `<vid>:<pid>` to the operator's answer. An absent key
|
|
9
|
+
* and an explicit `false` are the same fact (not opted in) and both are legal on
|
|
10
|
+
* disk: a `false` is what an opt-OUT leaves behind, and keeping it is what lets the
|
|
11
|
+
* shell reconciler prove it parsed a real answer rather than an empty document.
|
|
12
|
+
*/
|
|
13
|
+
export interface PersistedFccUnlockPolicy {
|
|
14
|
+
readonly schemaVersion: typeof FCC_UNLOCK_SCHEMA_VERSION;
|
|
15
|
+
readonly savedAtMs: number;
|
|
16
|
+
readonly unlock: Readonly<Record<string, boolean>>;
|
|
17
|
+
}
|
|
18
|
+
/** A metadata-only log event. Corruption NEVER carries the raw file content. */
|
|
19
|
+
export type FccUnlockLogEvent = {
|
|
20
|
+
readonly kind: 'corrupt-policy';
|
|
21
|
+
readonly bytes: number;
|
|
22
|
+
readonly reason: string;
|
|
23
|
+
};
|
|
24
|
+
export type FccUnlockLogger = (event: FccUnlockLogEvent) => void;
|
|
25
|
+
/** The persistence seam `setFccUnlockPolicy` drives. */
|
|
26
|
+
export interface FccUnlockPolicyStore {
|
|
27
|
+
/** Load persisted policy; an absent or unreadable file loads as EMPTY. */
|
|
28
|
+
load(nowMs: number): Promise<PersistedFccUnlockPolicy>;
|
|
29
|
+
/** Atomically write policy with mode 0600 (temp → chmod → rename). */
|
|
30
|
+
save(state: PersistedFccUnlockPolicy): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export interface FccUnlockPolicyFileStoreOptions {
|
|
33
|
+
readonly path?: string;
|
|
34
|
+
readonly logger?: FccUnlockLogger;
|
|
35
|
+
}
|
|
36
|
+
/** The `<vid>:<pid>` models the policy positively enables. Sorted, for stability. */
|
|
37
|
+
export declare function enabledFccUnlockKeys(state: PersistedFccUnlockPolicy): string[];
|
|
38
|
+
/** One model's answer. An unmentioned model is NOT enabled — absence is not consent. */
|
|
39
|
+
export declare function isFccUnlockEnabled(state: PersistedFccUnlockPolicy, key: string): boolean;
|
|
40
|
+
export declare function createFccUnlockPolicyFileStore(options?: FccUnlockPolicyFileStoreOptions): FccUnlockPolicyStore;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Durable persistence for the operator's FCC-auto-unlock POLICY.
|
|
2
|
+
//
|
|
3
|
+
// WHY THE FILE IS THE RECORD AND THE SYMLINK IS NOT. ModemManager's opt-in
|
|
4
|
+
// mechanism is a symlink in `/etc/ModemManager/fcc-unlock.d/<vid>:<pid>`. `/etc` is
|
|
5
|
+
// on the rootfs, and the rootfs is exactly what a RAUC A/B slot swap REPLACES
|
|
6
|
+
// (`image-building-pipeline/docs/partition-contract.md`), so that symlink survives a
|
|
7
|
+
// reboot and does NOT survive an OTA. `/data` is the only update-surviving store, so
|
|
8
|
+
// the durable record lives there and the symlink is a derived artifact re-created
|
|
9
|
+
// from it on every boot by `ceralive-fcc-reconcile`.
|
|
10
|
+
//
|
|
11
|
+
// The two hard guarantees are the SAME ones `backend/usage/policy-store.ts` makes,
|
|
12
|
+
// and deliberately implemented the same way so the pair can be read side by side:
|
|
13
|
+
// - MODE 0600 via temp → chmod → atomic rename, regardless of umask.
|
|
14
|
+
// - FAIL-SAFE ON CORRUPTION: an unparseable/incompatible file logs METADATA ONLY
|
|
15
|
+
// (byte length + a classification reason, never the content) and is treated as
|
|
16
|
+
// EMPTY. Note the divergence from the usage store, and it is load-bearing: the
|
|
17
|
+
// usage store REWRITES a fresh file, while this one leaves the damaged bytes on
|
|
18
|
+
// disk for an operator to look at and simply refuses to act on them. Enabling a
|
|
19
|
+
// regulatory-unlock procedure is not something to infer from a file we could not
|
|
20
|
+
// read, and silently replacing the evidence would make the next person's
|
|
21
|
+
// diagnosis impossible.
|
|
22
|
+
//
|
|
23
|
+
// A policy row carries ONLY a `<vid>:<pid>` MODEL identifier and a boolean. There is
|
|
24
|
+
// no per-unit identity here by construction — no serial, no ICCID, no ID_PATH —
|
|
25
|
+
// because ModemManager's mechanism is model-wide and a per-unit key would be a
|
|
26
|
+
// promise the dispatcher cannot keep.
|
|
27
|
+
import { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
28
|
+
import { dirname } from 'node:path';
|
|
29
|
+
import { isFccUnlockKey } from './coverage.js';
|
|
30
|
+
/** The current on-disk schema version. Bump when the persisted shape changes. */
|
|
31
|
+
export const FCC_UNLOCK_SCHEMA_VERSION = 1;
|
|
32
|
+
/** The pinned location of the policy of record. `/data` survives a slot swap. */
|
|
33
|
+
export const FCC_UNLOCK_POLICY_PATH = '/data/ceralive/fcc-unlock-policy.json';
|
|
34
|
+
function defaultLogger(event) {
|
|
35
|
+
console.warn(`[fcc-unlock-policy] ${event.kind}: bytes=${event.bytes} reason=${event.reason}`);
|
|
36
|
+
}
|
|
37
|
+
function emptyState(nowMs) {
|
|
38
|
+
return { schemaVersion: FCC_UNLOCK_SCHEMA_VERSION, savedAtMs: nowMs, unlock: {} };
|
|
39
|
+
}
|
|
40
|
+
/** A schema violation naming only the offending FIELD (never file content). */
|
|
41
|
+
class FccPolicySchemaError extends Error {
|
|
42
|
+
constructor(field) {
|
|
43
|
+
super(`schema-mismatch: ${field}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse + validate the document. Throws `FccPolicySchemaError` (metadata-only).
|
|
48
|
+
*
|
|
49
|
+
* WHOLE-DOCUMENT rejection, never per-key skipping: a half-applied policy is a
|
|
50
|
+
* policy nobody wrote, and the shell reconciler makes the same all-or-nothing
|
|
51
|
+
* judgement, so the two halves agree on what a damaged file means.
|
|
52
|
+
*/
|
|
53
|
+
function validate(raw) {
|
|
54
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
55
|
+
throw new FccPolicySchemaError('document');
|
|
56
|
+
}
|
|
57
|
+
const doc = raw;
|
|
58
|
+
if (doc.schemaVersion !== FCC_UNLOCK_SCHEMA_VERSION) {
|
|
59
|
+
throw new FccPolicySchemaError('schemaVersion');
|
|
60
|
+
}
|
|
61
|
+
if (typeof doc.savedAtMs !== 'number' || !Number.isFinite(doc.savedAtMs)) {
|
|
62
|
+
throw new FccPolicySchemaError('savedAtMs');
|
|
63
|
+
}
|
|
64
|
+
if (typeof doc.unlock !== 'object' || doc.unlock === null || Array.isArray(doc.unlock)) {
|
|
65
|
+
throw new FccPolicySchemaError('unlock');
|
|
66
|
+
}
|
|
67
|
+
const unlock = {};
|
|
68
|
+
for (const [key, value] of Object.entries(doc.unlock)) {
|
|
69
|
+
if (!isFccUnlockKey(key)) {
|
|
70
|
+
throw new FccPolicySchemaError('unlock.key');
|
|
71
|
+
}
|
|
72
|
+
if (typeof value !== 'boolean') {
|
|
73
|
+
throw new FccPolicySchemaError('unlock.value');
|
|
74
|
+
}
|
|
75
|
+
unlock[key] = value;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
schemaVersion: FCC_UNLOCK_SCHEMA_VERSION,
|
|
79
|
+
savedAtMs: doc.savedAtMs,
|
|
80
|
+
unlock,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Classify a load failure into a metadata-only reason string (no raw content). */
|
|
84
|
+
function classifyFailure(error) {
|
|
85
|
+
if (error instanceof FccPolicySchemaError) {
|
|
86
|
+
return error.message;
|
|
87
|
+
}
|
|
88
|
+
if (error instanceof SyntaxError) {
|
|
89
|
+
const offset = /position (\d+)/.exec(error.message)?.[1];
|
|
90
|
+
return offset !== undefined ? `invalid-json at offset ${offset}` : 'invalid-json';
|
|
91
|
+
}
|
|
92
|
+
return 'unreadable';
|
|
93
|
+
}
|
|
94
|
+
/** The `<vid>:<pid>` models the policy positively enables. Sorted, for stability. */
|
|
95
|
+
export function enabledFccUnlockKeys(state) {
|
|
96
|
+
return Object.entries(state.unlock)
|
|
97
|
+
.filter(([, enabled]) => enabled)
|
|
98
|
+
.map(([key]) => key)
|
|
99
|
+
.sort();
|
|
100
|
+
}
|
|
101
|
+
/** One model's answer. An unmentioned model is NOT enabled — absence is not consent. */
|
|
102
|
+
export function isFccUnlockEnabled(state, key) {
|
|
103
|
+
return state.unlock[key] === true;
|
|
104
|
+
}
|
|
105
|
+
export function createFccUnlockPolicyFileStore(options = {}) {
|
|
106
|
+
const logger = options.logger ?? defaultLogger;
|
|
107
|
+
const path = options.path ?? FCC_UNLOCK_POLICY_PATH;
|
|
108
|
+
async function writeAtomic(state) {
|
|
109
|
+
await mkdir(dirname(path), { recursive: true });
|
|
110
|
+
const tmp = `${path}.tmp`;
|
|
111
|
+
// The trailing newline is for the shell reconciler's benefit, not decoration:
|
|
112
|
+
// it reads the file with `tr -d`, and a newline-terminated document is what a
|
|
113
|
+
// human `cat`ing it on a board expects to see.
|
|
114
|
+
await writeFile(tmp, `${JSON.stringify(state)}\n`);
|
|
115
|
+
// chmod AFTER the write (not an open flag) so mode is 0600 regardless of umask.
|
|
116
|
+
await chmod(tmp, 0o600);
|
|
117
|
+
await rename(tmp, path);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
async load(nowMs) {
|
|
121
|
+
let text;
|
|
122
|
+
try {
|
|
123
|
+
text = await readFile(path, 'utf8');
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Absent (or unreadable) → EMPTY, which activates nothing. This is the
|
|
127
|
+
// state on every device that never opted in, and it is the safe default.
|
|
128
|
+
return emptyState(nowMs);
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return validate(JSON.parse(text));
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
logger({
|
|
135
|
+
kind: 'corrupt-policy',
|
|
136
|
+
bytes: Buffer.byteLength(text, 'utf8'),
|
|
137
|
+
reason: classifyFailure(error),
|
|
138
|
+
});
|
|
139
|
+
// Deliberately NOT rewritten — see the header. Refuse to act, keep the
|
|
140
|
+
// evidence, and let the next write replace it wholesale.
|
|
141
|
+
return emptyState(nowMs);
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
save: writeAtomic,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FccUnlockPolicyStore, PersistedFccUnlockPolicy } from './policy-store.js';
|
|
2
|
+
export interface SetFccUnlockPolicyDeps {
|
|
3
|
+
readonly store: FccUnlockPolicyStore;
|
|
4
|
+
/** Injectable clock (defaults to `Date.now`). */
|
|
5
|
+
readonly now?: () => number;
|
|
6
|
+
}
|
|
7
|
+
export interface SetFccUnlockPolicyRequest {
|
|
8
|
+
readonly vid: string;
|
|
9
|
+
readonly pid: string;
|
|
10
|
+
readonly enabled: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type SetFccUnlockPolicyRejection = 'invalid-vid-pid' | 'not-covered';
|
|
13
|
+
export type SetFccUnlockPolicyResult = {
|
|
14
|
+
readonly status: 'applied';
|
|
15
|
+
/** The dispatcher key this write is about, normalized. */
|
|
16
|
+
readonly key: string;
|
|
17
|
+
readonly enabled: boolean;
|
|
18
|
+
/** The whole document now on disk, so a caller need not re-read it. */
|
|
19
|
+
readonly policy: PersistedFccUnlockPolicy;
|
|
20
|
+
/**
|
|
21
|
+
* True when the persisted value CHANGED. A caller uses this to decide
|
|
22
|
+
* whether the modem needs a re-probe: ModemManager runs the dispatcher
|
|
23
|
+
* during initialization only, so a genuine change needs
|
|
24
|
+
* `mmcli -m <id> --disable && --enable` (or a replug) to take effect on an
|
|
25
|
+
* already-enumerated modem — and an unchanged write must not cost one.
|
|
26
|
+
*/
|
|
27
|
+
readonly changed: boolean;
|
|
28
|
+
} | {
|
|
29
|
+
readonly status: 'rejected';
|
|
30
|
+
readonly reason: SetFccUnlockPolicyRejection;
|
|
31
|
+
};
|
|
32
|
+
export declare function setFccUnlockPolicy(request: SetFccUnlockPolicyRequest, deps: SetFccUnlockPolicyDeps): Promise<SetFccUnlockPolicyResult>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// `setFccUnlockPolicy` — the WRITE half of the FCC auto-unlock surface.
|
|
2
|
+
//
|
|
3
|
+
// TYPED RESULTS, NEVER A THROW ON BAD INPUT. Following the `PowerHook` and
|
|
4
|
+
// `setUsagePolicy` precedents, a malformed key or an uncovered model is a `rejected`
|
|
5
|
+
// result carrying a named reason rather than an exception — this is called from an
|
|
6
|
+
// RPC boundary, where a throw becomes an opaque 500.
|
|
7
|
+
//
|
|
8
|
+
// THE COVERAGE CHECK IS PART OF THE WRITE, not a UI nicety. Persisting `true` for a
|
|
9
|
+
// model ModemManager ships no procedure for would leave the operator staring at an
|
|
10
|
+
// enabled toggle that provably cannot do anything: the reconciler would find no
|
|
11
|
+
// `<vid>:<pid>` in the available tier and skip it forever, silently. Refusing at the
|
|
12
|
+
// write is the only place that fact can be reported to the person who asked for it.
|
|
13
|
+
//
|
|
14
|
+
// Disabling is deliberately NOT coverage-checked. A `false` must always be
|
|
15
|
+
// persistable — including for a model whose coverage answer has since changed, or
|
|
16
|
+
// which a previous release wrote — because a fail-closed opt-OUT is not a thing.
|
|
17
|
+
import { normalizeVidPid, resolveFccUnlockCoverage } from './coverage.js';
|
|
18
|
+
export async function setFccUnlockPolicy(request, deps) {
|
|
19
|
+
const key = normalizeVidPid(request.vid, request.pid);
|
|
20
|
+
if (key === undefined) {
|
|
21
|
+
return { status: 'rejected', reason: 'invalid-vid-pid' };
|
|
22
|
+
}
|
|
23
|
+
if (request.enabled && resolveFccUnlockCoverage(request.vid, request.pid) !== 'present') {
|
|
24
|
+
return { status: 'rejected', reason: 'not-covered' };
|
|
25
|
+
}
|
|
26
|
+
const now = deps.now ?? Date.now;
|
|
27
|
+
const nowMs = now();
|
|
28
|
+
const current = await deps.store.load(nowMs);
|
|
29
|
+
const changed = (current.unlock[key] === true) !== request.enabled;
|
|
30
|
+
const next = {
|
|
31
|
+
schemaVersion: current.schemaVersion,
|
|
32
|
+
savedAtMs: nowMs,
|
|
33
|
+
unlock: { ...current.unlock, [key]: request.enabled },
|
|
34
|
+
};
|
|
35
|
+
await deps.store.save(next);
|
|
36
|
+
return { status: 'applied', key, enabled: request.enabled, policy: next, changed };
|
|
37
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare function parseHilinkXmlValue(body: string, tag: string): string | undefined;
|
|
2
|
+
export type HilinkSessionDocument = {
|
|
3
|
+
readonly cookie: string;
|
|
4
|
+
readonly token: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function parseHilinkSession(body: string): HilinkSessionDocument | undefined;
|
|
7
|
+
export type HilinkUserState = {
|
|
8
|
+
readonly state: string;
|
|
9
|
+
readonly passwordType: 3 | 4;
|
|
10
|
+
};
|
|
11
|
+
export declare function parseHilinkUserState(body: string): HilinkUserState | undefined;
|
|
12
|
+
export type HilinkProtocolUnknownReason = 'unsupported' | 'not-reported' | 'malformed' | 'auth-expired' | 'unreachable';
|
|
13
|
+
export type HilinkDataCapability = {
|
|
14
|
+
readonly state: 'reported';
|
|
15
|
+
readonly enabled: boolean;
|
|
16
|
+
} | {
|
|
17
|
+
readonly state: 'unavailable';
|
|
18
|
+
readonly reason: HilinkProtocolUnknownReason | 'refused';
|
|
19
|
+
readonly code?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function parseHilinkDataCapability(body: string): HilinkDataCapability;
|
|
22
|
+
export type HilinkNetModeCapability = {
|
|
23
|
+
readonly state: 'reported';
|
|
24
|
+
readonly modes: readonly {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly name?: string;
|
|
27
|
+
}[];
|
|
28
|
+
readonly current?: string;
|
|
29
|
+
} | {
|
|
30
|
+
readonly state: 'unavailable';
|
|
31
|
+
readonly reason: HilinkProtocolUnknownReason | 'refused';
|
|
32
|
+
readonly code?: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function parseHilinkCapabilities(input: {
|
|
35
|
+
readonly netModeList: string;
|
|
36
|
+
readonly netMode?: string;
|
|
37
|
+
}): {
|
|
38
|
+
readonly net_mode: HilinkNetModeCapability;
|
|
39
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export function parseHilinkXmlValue(body, tag) {
|
|
2
|
+
const match = body.match(new RegExp(`<${tag}>([^<]*)</${tag}>`, 'i'));
|
|
3
|
+
return match?.[1]?.trim();
|
|
4
|
+
}
|
|
5
|
+
export function parseHilinkSession(body) {
|
|
6
|
+
const cookie = parseHilinkXmlValue(body, 'SesInfo');
|
|
7
|
+
const token = parseHilinkXmlValue(body, 'TokInfo');
|
|
8
|
+
return cookie === undefined || cookie === '' || token === undefined || token === ''
|
|
9
|
+
? undefined
|
|
10
|
+
: { cookie, token };
|
|
11
|
+
}
|
|
12
|
+
export function parseHilinkUserState(body) {
|
|
13
|
+
const state = parseHilinkXmlValue(body, 'State');
|
|
14
|
+
const rawPasswordType = parseHilinkXmlValue(body, 'password_type');
|
|
15
|
+
if (state === undefined || (rawPasswordType !== '3' && rawPasswordType !== '4'))
|
|
16
|
+
return undefined;
|
|
17
|
+
return { state, passwordType: rawPasswordType === '3' ? 3 : 4 };
|
|
18
|
+
}
|
|
19
|
+
export function parseHilinkDataCapability(body) {
|
|
20
|
+
const code = parseHilinkXmlValue(body, 'code');
|
|
21
|
+
if (code === '125002')
|
|
22
|
+
return { state: 'unavailable', reason: 'auth-expired' };
|
|
23
|
+
if (code !== undefined)
|
|
24
|
+
return { state: 'unavailable', reason: 'refused', code };
|
|
25
|
+
const value = parseHilinkXmlValue(body, 'dataswitch');
|
|
26
|
+
if (value === undefined)
|
|
27
|
+
return { state: 'unavailable', reason: body === '' ? 'unreachable' : 'malformed' };
|
|
28
|
+
if (value !== '0' && value !== '1')
|
|
29
|
+
return { state: 'unavailable', reason: 'malformed' };
|
|
30
|
+
return { state: 'reported', enabled: value === '1' };
|
|
31
|
+
}
|
|
32
|
+
export function parseHilinkCapabilities(input) {
|
|
33
|
+
const code = parseHilinkXmlValue(input.netModeList, 'code');
|
|
34
|
+
if (code === '125002')
|
|
35
|
+
return { net_mode: { state: 'unavailable', reason: 'auth-expired' } };
|
|
36
|
+
if (code !== undefined)
|
|
37
|
+
return { net_mode: { state: 'unavailable', reason: 'refused', code } };
|
|
38
|
+
if (input.netModeList.trim() === '')
|
|
39
|
+
return { net_mode: { state: 'unavailable', reason: 'unreachable' } };
|
|
40
|
+
// `malformed` is a statement about the BODY — something that is not this API
|
|
41
|
+
// answered. A `<response>` carrying no mode list IS this API, saying nothing,
|
|
42
|
+
// which is `not-reported` below.
|
|
43
|
+
if (!/<response>/i.test(input.netModeList))
|
|
44
|
+
return { net_mode: { state: 'unavailable', reason: 'malformed' } };
|
|
45
|
+
const modes = [...input.netModeList.matchAll(/<NetworkMode>([\s\S]*?)<\/NetworkMode>/gi)].flatMap((match) => {
|
|
46
|
+
const id = parseHilinkXmlValue(match[1] ?? '', 'Index');
|
|
47
|
+
if (id === undefined || id === '')
|
|
48
|
+
return [];
|
|
49
|
+
const name = parseHilinkXmlValue(match[1] ?? '', 'Name');
|
|
50
|
+
return name === undefined || name === '' ? [{ id }] : [{ id, name }];
|
|
51
|
+
});
|
|
52
|
+
if (modes.length === 0)
|
|
53
|
+
return { net_mode: { state: 'unavailable', reason: 'not-reported' } };
|
|
54
|
+
const current = parseHilinkXmlValue(input.netMode ?? '', 'NetworkMode');
|
|
55
|
+
return current === undefined || current === ''
|
|
56
|
+
? { net_mode: { state: 'reported', modes } }
|
|
57
|
+
: { net_mode: { state: 'reported', modes, current } };
|
|
58
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// `@ceralive/modem-control/hardware` — the per-SKU hardware model.
|
|
2
|
+
//
|
|
3
|
+
// This subpath is the narrow entry for everything keyed on the PHYSICAL unit rather
|
|
4
|
+
// than on a live D-Bus object: which USB composition a SKU may be switched into and
|
|
5
|
+
// which transitions were certified for it (`../usb-mode`), and the MMModemBand
|
|
6
|
+
// vocabulary plus the per-SKU band-lock certification catalog (`../band`).
|
|
7
|
+
//
|
|
8
|
+
// Both halves are evidence-gated catalogs plus their pure lookups — no transport, no
|
|
9
|
+
// mutation verb. The D-Bus verbs that ACT on these facts stay where they live
|
|
10
|
+
// (`../backend/mm-mutations.ts`, declared on `ModemManagerPort`); a consumer that only
|
|
11
|
+
// needs to know what a SKU is capable of should not have to import a bus client to
|
|
12
|
+
// find out. That asymmetry is the reason this entry exists.
|
|
13
|
+
export * from '../band/index.js';
|
|
14
|
+
export * from '../usb-mode/index.js';
|
|
15
|
+
export * from './router-parsers.js';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export * from './hilink-protocol.js';
|
|
2
|
+
export type SimPresence = 'present' | 'absent' | 'unknown';
|
|
3
|
+
export type SimPresenceFacts = {
|
|
4
|
+
readonly sim?: string;
|
|
5
|
+
readonly simSlots?: readonly string[];
|
|
6
|
+
readonly failedReason?: string;
|
|
7
|
+
};
|
|
8
|
+
/** The mmcli spelling of `MM_MODEM_STATE_FAILED_REASON_SIM_MISSING` — the ONLY proof of absence. */
|
|
9
|
+
export declare const SIM_MISSING_FAILED_REASON = "sim-missing";
|
|
10
|
+
/** The fields a presence decision may be drawn from, in the order they are inspected. */
|
|
11
|
+
export declare const SIM_PRESENCE_FIELDS: readonly ['sim', 'simSlots', 'failedReason'];
|
|
12
|
+
export type SimPresenceField = (typeof SIM_PRESENCE_FIELDS)[number];
|
|
13
|
+
/**
|
|
14
|
+
* WHICH FACT decided a SIM presence — the whole point of this type.
|
|
15
|
+
*
|
|
16
|
+
* `absent` is reachable through exactly ONE member (`state-failed-reason`), so a
|
|
17
|
+
* consumer can prove that no code path inferred "there is no SIM" from a blank or
|
|
18
|
+
* missing field. A modem that exports `Sim: '/'` and says nothing else is
|
|
19
|
+
* `no-evidence`/`unknown`: an empty object path is ModemManager's answer for "no SIM
|
|
20
|
+
* object is bound right now", which a modem also reports while it is still
|
|
21
|
+
* initializing, while its SIM is locked out, and while a slot switch is in flight.
|
|
22
|
+
*
|
|
23
|
+
* `vendor-code-unclaimed` is the router half. HiLink, goform and HIMI each report
|
|
24
|
+
* their own presence code with vendor semantics no migrated decoder covers, so the
|
|
25
|
+
* code is NAMED here and its value stays verbatim in the diagnostics block, rather
|
|
26
|
+
* than being guessed into a presence.
|
|
27
|
+
*/
|
|
28
|
+
export type SimPresenceEvidence = {
|
|
29
|
+
readonly kind: 'sim-object-path';
|
|
30
|
+
readonly field: 'sim';
|
|
31
|
+
readonly value: string;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: 'sim-slot-object-path';
|
|
34
|
+
readonly field: 'simSlots';
|
|
35
|
+
readonly value: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: 'state-failed-reason';
|
|
38
|
+
readonly field: 'failedReason';
|
|
39
|
+
readonly value: typeof SIM_MISSING_FAILED_REASON;
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: 'no-evidence';
|
|
42
|
+
readonly inspected: readonly SimPresenceField[];
|
|
43
|
+
} | {
|
|
44
|
+
readonly kind: 'vendor-code-unclaimed';
|
|
45
|
+
readonly field: string;
|
|
46
|
+
};
|
|
47
|
+
export type SimPresenceReading = {
|
|
48
|
+
readonly presence: SimPresence;
|
|
49
|
+
readonly evidence: SimPresenceEvidence;
|
|
50
|
+
};
|
|
51
|
+
/** The presence decision together with the fact that produced it. */
|
|
52
|
+
export declare function readSimPresence(facts: SimPresenceFacts): SimPresenceReading;
|
|
53
|
+
export declare function deriveSimPresence(facts: SimPresenceFacts): SimPresence;
|
|
54
|
+
export type RouterSignalUnknownReason = 'unsupported' | 'not-reported' | 'malformed' | 'auth-expired' | 'unreachable';
|
|
55
|
+
export type RouterSignalMetric = {
|
|
56
|
+
readonly state: 'known';
|
|
57
|
+
readonly value: number;
|
|
58
|
+
} | {
|
|
59
|
+
readonly state: 'unknown';
|
|
60
|
+
readonly reason: RouterSignalUnknownReason;
|
|
61
|
+
};
|
|
62
|
+
export type RouterSignalModel = {
|
|
63
|
+
readonly provenance: 'hilink-admin-api' | 'zte-goform' | 'ufi-himiapi';
|
|
64
|
+
readonly freshness: 'live' | 'unknown';
|
|
65
|
+
readonly bars: RouterSignalMetric;
|
|
66
|
+
readonly max_bars: RouterSignalMetric;
|
|
67
|
+
readonly dbm: RouterSignalMetric;
|
|
68
|
+
readonly rsrp: RouterSignalMetric;
|
|
69
|
+
readonly rsrq: RouterSignalMetric;
|
|
70
|
+
readonly snr: RouterSignalMetric;
|
|
71
|
+
readonly sinr: RouterSignalMetric;
|
|
72
|
+
};
|
|
73
|
+
export declare function parseHilinkSignal(input: {
|
|
74
|
+
readonly status: string;
|
|
75
|
+
readonly signal: string;
|
|
76
|
+
}): RouterSignalModel;
|
|
77
|
+
export declare function parseZteSignal(body: string): RouterSignalModel;
|
|
78
|
+
export declare function parseUfiSignal(input: {
|
|
79
|
+
readonly sysinfo: string;
|
|
80
|
+
readonly overview: string;
|
|
81
|
+
readonly status: string;
|
|
82
|
+
}): RouterSignalModel;
|
|
83
|
+
export type RouterDetails = Readonly<Record<string, string>>;
|
|
84
|
+
export declare function parseZteDetails(body: string): RouterDetails | undefined;
|
|
85
|
+
export declare function parseUfiDetails(input: {
|
|
86
|
+
readonly overview?: string;
|
|
87
|
+
readonly sysinfo?: string;
|
|
88
|
+
readonly produceInfo?: string;
|
|
89
|
+
}): RouterDetails | undefined;
|