@ceralive/modem-control 0.2.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +317 -0
- package/dist/backend/at-lease.d.ts +57 -0
- package/dist/backend/at-lease.js +109 -0
- package/dist/backend/cell-info.d.ts +46 -0
- package/dist/backend/cell-info.js +124 -0
- package/dist/backend/constants.d.ts +24 -0
- package/{src/backend/constants.ts → dist/backend/constants.js} +4 -9
- package/dist/backend/device-classifier.d.ts +46 -0
- package/dist/backend/device-classifier.js +258 -0
- package/dist/backend/enrichment.d.ts +28 -0
- package/dist/backend/enrichment.js +59 -0
- package/dist/backend/features.d.ts +61 -0
- package/dist/backend/features.js +109 -0
- package/dist/backend/identity-ladder.d.ts +57 -0
- package/dist/backend/identity-ladder.js +158 -0
- package/dist/backend/identity-registry.d.ts +51 -0
- package/dist/backend/identity-registry.js +101 -0
- package/dist/backend/index.d.ts +30 -0
- package/dist/backend/index.js +35 -0
- package/dist/backend/lifecycle-interlock.d.ts +25 -0
- package/dist/backend/lifecycle-interlock.js +18 -0
- package/dist/backend/managed-objects.d.ts +39 -0
- package/dist/backend/managed-objects.js +82 -0
- package/dist/backend/mapping.d.ts +11 -0
- package/dist/backend/mapping.js +148 -0
- package/dist/backend/mm-backend.d.ts +44 -0
- package/dist/backend/mm-backend.js +154 -0
- package/dist/backend/mm-location.d.ts +21 -0
- package/dist/backend/mm-location.js +237 -0
- package/dist/backend/mm-mutations.d.ts +42 -0
- package/dist/backend/mm-mutations.js +259 -0
- package/dist/backend/modem-actor.d.ts +41 -0
- package/dist/backend/modem-actor.js +78 -0
- package/dist/backend/nm-auto-apn.d.ts +54 -0
- package/dist/backend/nm-auto-apn.js +124 -0
- package/dist/backend/nm-gsm-fields.d.ts +23 -0
- package/dist/backend/nm-gsm-fields.js +107 -0
- package/dist/backend/nmcli-nm-port.d.ts +28 -0
- package/dist/backend/nmcli-nm-port.js +173 -0
- package/dist/backend/nmcli-runner.d.ts +24 -0
- package/dist/backend/nmcli-runner.js +35 -0
- package/dist/backend/observer.d.ts +37 -0
- package/dist/backend/observer.js +219 -0
- package/dist/backend/power-contract.d.ts +49 -0
- package/dist/backend/power-contract.js +34 -0
- package/dist/backend/recovery-attribution.d.ts +32 -0
- package/dist/backend/recovery-attribution.js +57 -0
- package/dist/backend/recovery-budget.d.ts +45 -0
- package/dist/backend/recovery-budget.js +44 -0
- package/dist/backend/recovery-ladder.d.ts +94 -0
- package/dist/backend/recovery-ladder.js +116 -0
- package/dist/backend/router-ethernet.d.ts +19 -0
- package/dist/backend/router-ethernet.js +66 -0
- package/dist/backend/row-store.d.ts +13 -0
- package/dist/backend/row-store.js +82 -0
- package/dist/backend/signal-setup.d.ts +30 -0
- package/dist/backend/signal-setup.js +92 -0
- package/dist/backend/sim-unlock.d.ts +13 -0
- package/dist/backend/sim-unlock.js +153 -0
- package/dist/backend/transition-preconditions.d.ts +76 -0
- package/dist/backend/transition-preconditions.js +64 -0
- package/dist/backend/usage/accounting.d.ts +39 -0
- package/dist/backend/usage/accounting.js +73 -0
- package/dist/backend/usage/billing-cycle.d.ts +11 -0
- package/dist/backend/usage/billing-cycle.js +39 -0
- package/dist/backend/usage/boot-id.d.ts +6 -0
- package/{src/backend/usage/boot-id.ts → dist/backend/usage/boot-id.js} +7 -7
- package/dist/backend/usage/index.d.ts +8 -0
- package/dist/backend/usage/index.js +11 -0
- package/dist/backend/usage/policy-store.d.ts +50 -0
- package/dist/backend/usage/policy-store.js +161 -0
- package/dist/backend/usage/policy-write.d.ts +65 -0
- package/dist/backend/usage/policy-write.js +112 -0
- package/dist/backend/usage/proc-net-dev.d.ts +18 -0
- package/{src/backend/usage/proc-net-dev.ts → dist/backend/usage/proc-net-dev.js} +39 -47
- package/dist/backend/usage/sampler.d.ts +75 -0
- package/dist/backend/usage/sampler.js +211 -0
- package/dist/backend/usage/store.d.ts +38 -0
- package/dist/backend/usage/store.js +126 -0
- package/dist/backend/usb-device-snapshot.d.ts +31 -0
- package/dist/backend/usb-device-snapshot.js +1 -0
- package/dist/backend/usb-enumerator.d.ts +21 -0
- package/dist/backend/usb-enumerator.js +153 -0
- package/dist/backend/usb-mode-transition.d.ts +29 -0
- package/dist/backend/usb-mode-transition.js +196 -0
- package/dist/band/band-names.d.ts +42 -0
- package/dist/band/band-names.js +150 -0
- package/dist/band/certification.d.ts +84 -0
- package/dist/band/certification.js +127 -0
- package/dist/band/certified-bands.json +4 -0
- package/dist/band/index.d.ts +2 -0
- package/dist/band/index.js +8 -0
- package/dist/capability/detect.d.ts +52 -0
- package/dist/capability/detect.js +86 -0
- package/dist/capability/five-g-preference.d.ts +104 -0
- package/dist/capability/five-g-preference.js +171 -0
- package/dist/capability/index.d.ts +3 -0
- package/dist/capability/index.js +10 -0
- package/dist/capability/support-claim.d.ts +39 -0
- package/dist/capability/support-claim.js +81 -0
- package/dist/domain/brand.d.ts +10 -0
- package/dist/domain/brand.js +21 -0
- package/dist/domain/errors.d.ts +32 -0
- package/dist/domain/errors.js +48 -0
- package/dist/domain/generation.d.ts +8 -0
- package/dist/domain/generation.js +12 -0
- package/dist/domain/guards.d.ts +6 -0
- package/dist/domain/guards.js +127 -0
- package/dist/domain/identity.d.ts +109 -0
- package/dist/domain/identity.js +86 -0
- package/dist/domain/index.d.ts +14 -0
- package/dist/domain/index.js +18 -0
- package/dist/domain/mm-enums.d.ts +12 -0
- package/dist/domain/mm-enums.js +139 -0
- package/dist/domain/modem-presentation.d.ts +10 -0
- package/dist/domain/modem-presentation.js +39 -0
- package/dist/domain/observation.d.ts +39 -0
- package/dist/domain/observation.js +4 -0
- package/dist/domain/operation.d.ts +118 -0
- package/dist/domain/operation.js +85 -0
- package/dist/domain/physical-identity.d.ts +43 -0
- package/dist/domain/physical-identity.js +113 -0
- package/{src/domain/policy.ts → dist/domain/policy.d.ts} +34 -69
- package/dist/domain/policy.js +38 -0
- package/dist/domain/shadow-divergence.d.ts +27 -0
- package/dist/domain/shadow-divergence.js +70 -0
- package/dist/domain/snapshot.d.ts +53 -0
- package/dist/domain/snapshot.js +75 -0
- package/{src/domain/state.ts → dist/domain/state.d.ts} +23 -122
- package/dist/domain/state.js +38 -0
- package/dist/fcc/coverage.d.ts +63 -0
- package/dist/fcc/coverage.js +102 -0
- package/dist/fcc/index.d.ts +3 -0
- package/dist/fcc/index.js +12 -0
- package/dist/fcc/policy-store.d.ts +40 -0
- package/dist/fcc/policy-store.js +146 -0
- package/dist/fcc/policy-write.d.ts +32 -0
- package/dist/fcc/policy-write.js +37 -0
- package/dist/hardware/hilink-protocol.d.ts +39 -0
- package/dist/hardware/hilink-protocol.js +58 -0
- package/dist/hardware/index.d.ts +3 -0
- package/dist/hardware/index.js +15 -0
- package/dist/hardware/router-parsers.d.ts +89 -0
- package/dist/hardware/router-parsers.js +234 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +26 -0
- package/dist/journal/codec.d.ts +44 -0
- package/dist/journal/codec.js +198 -0
- package/dist/journal/engine.d.ts +28 -0
- package/dist/journal/engine.js +68 -0
- package/dist/journal/entry.d.ts +74 -0
- package/dist/journal/entry.js +56 -0
- package/dist/journal/index.d.ts +6 -0
- package/dist/journal/index.js +6 -0
- package/dist/journal/legacy-ceraui.d.ts +73 -0
- package/dist/journal/legacy-ceraui.js +227 -0
- package/dist/journal/recovery.d.ts +58 -0
- package/dist/journal/recovery.js +117 -0
- package/dist/journal/store.d.ts +55 -0
- package/dist/journal/store.js +150 -0
- package/dist/location/fix-state.d.ts +53 -0
- package/dist/location/fix-state.js +75 -0
- package/dist/location/index.d.ts +2 -0
- package/dist/location/index.js +8 -0
- package/dist/location/nmea.d.ts +10 -0
- package/dist/location/nmea.js +89 -0
- package/dist/observations/envelope.d.ts +63 -0
- package/dist/observations/envelope.js +77 -0
- package/dist/observations/freshness.d.ts +28 -0
- package/dist/observations/freshness.js +76 -0
- package/dist/observations/index.d.ts +13 -0
- package/dist/observations/index.js +24 -0
- package/dist/observations/metric.d.ts +47 -0
- package/dist/observations/metric.js +73 -0
- package/dist/observations/model.d.ts +80 -0
- package/dist/observations/model.js +11 -0
- package/dist/observations/provenance.d.ts +94 -0
- package/dist/observations/provenance.js +67 -0
- package/dist/observations/raw.d.ts +42 -0
- package/dist/observations/raw.js +146 -0
- package/dist/observations/reading.d.ts +51 -0
- package/dist/observations/reading.js +65 -0
- package/dist/observations/sources/hilink.d.ts +10 -0
- package/dist/observations/sources/hilink.js +84 -0
- package/dist/observations/sources/modemmanager.d.ts +18 -0
- package/dist/observations/sources/modemmanager.js +239 -0
- package/dist/observations/sources/router-shared.d.ts +29 -0
- package/dist/observations/sources/router-shared.js +68 -0
- package/dist/observations/sources/ufi.d.ts +10 -0
- package/dist/observations/sources/ufi.js +111 -0
- package/dist/observations/sources/zte.d.ts +7 -0
- package/dist/observations/sources/zte.js +71 -0
- package/dist/observations/state-separation.d.ts +64 -0
- package/dist/observations/state-separation.js +52 -0
- package/dist/operations/contracts.d.ts +72 -0
- package/dist/operations/contracts.js +1 -0
- package/dist/operations/index.d.ts +1 -0
- package/dist/operations/index.js +1 -0
- package/dist/operations/operation-engine.d.ts +16 -0
- package/dist/operations/operation-engine.js +194 -0
- package/dist/ports/index.d.ts +12 -0
- package/{src/ports/index.ts → dist/ports/index.js} +12 -8
- package/dist/ports/location.d.ts +87 -0
- package/dist/ports/location.js +36 -0
- package/dist/ports/modem-manager.d.ts +89 -0
- package/dist/ports/modem-manager.js +9 -0
- package/dist/ports/mutation-admission.d.ts +27 -0
- package/dist/ports/mutation-admission.js +9 -0
- package/dist/ports/network-manager.d.ts +68 -0
- package/dist/ports/network-manager.js +13 -0
- package/{src/ports/observation.ts → dist/ports/observation.d.ts} +16 -27
- package/dist/ports/observation.js +7 -0
- package/dist/ports/ops.d.ts +44 -0
- package/dist/ports/ops.js +16 -0
- package/{src/ports/receipts.ts → dist/ports/receipts.d.ts} +5 -27
- package/dist/ports/receipts.js +9 -0
- package/dist/ports/reconcile.d.ts +33 -0
- package/dist/ports/reconcile.js +200 -0
- package/dist/ports/resource-ownership.d.ts +29 -0
- package/dist/ports/resource-ownership.js +1 -0
- package/dist/ports/router.d.ts +19 -0
- package/dist/ports/router.js +7 -0
- package/dist/ports/sms.d.ts +64 -0
- package/dist/ports/sms.js +24 -0
- package/dist/ports/uhubctl.d.ts +6 -0
- package/dist/ports/uhubctl.js +1 -0
- package/dist/providers/contracts.d.ts +124 -0
- package/dist/providers/contracts.js +10 -0
- package/dist/providers/huawei-hilink/index.d.ts +2 -0
- package/dist/providers/huawei-hilink/index.js +2 -0
- package/dist/providers/huawei-hilink/operations.d.ts +20 -0
- package/dist/providers/huawei-hilink/operations.js +56 -0
- package/dist/providers/huawei-hilink/provider.d.ts +52 -0
- package/dist/providers/huawei-hilink/provider.js +76 -0
- package/dist/providers/huawei-hilink/runtime.d.ts +22 -0
- package/dist/providers/huawei-hilink/runtime.js +171 -0
- package/dist/providers/huawei-hilink/session.d.ts +28 -0
- package/dist/providers/huawei-hilink/session.js +120 -0
- package/dist/providers/huawei-hilink/transport.d.ts +19 -0
- package/dist/providers/huawei-hilink/transport.js +1 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/matcher.d.ts +3 -0
- package/dist/providers/matcher.js +205 -0
- package/dist/providers/modem-manager/errors.d.ts +7 -0
- package/dist/providers/modem-manager/errors.js +37 -0
- package/dist/providers/modem-manager/generic-operations.d.ts +8 -0
- package/dist/providers/modem-manager/generic-operations.js +207 -0
- package/dist/providers/modem-manager/index.d.ts +3 -0
- package/dist/providers/modem-manager/index.js +3 -0
- package/dist/providers/modem-manager/module-operations.d.ts +21 -0
- package/dist/providers/modem-manager/module-operations.js +118 -0
- package/dist/providers/modem-manager/provider.d.ts +39 -0
- package/dist/providers/modem-manager/provider.js +152 -0
- package/dist/providers/modem-manager/snapshot.d.ts +5 -0
- package/dist/providers/modem-manager/snapshot.js +204 -0
- package/dist/providers/modem-manager/types.d.ts +135 -0
- package/dist/providers/modem-manager/types.js +1 -0
- package/dist/providers/network-manager/adapter.d.ts +71 -0
- package/dist/providers/network-manager/adapter.js +348 -0
- package/dist/providers/network-manager/index.d.ts +2 -0
- package/dist/providers/network-manager/index.js +2 -0
- package/dist/providers/network-manager/types.d.ts +163 -0
- package/dist/providers/network-manager/types.js +77 -0
- package/dist/providers/registry.d.ts +13 -0
- package/dist/providers/registry.js +33 -0
- package/dist/providers/ufi-himi/index.d.ts +6 -0
- package/dist/providers/ufi-himi/index.js +6 -0
- package/dist/providers/ufi-himi/operations.d.ts +41 -0
- package/dist/providers/ufi-himi/operations.js +66 -0
- package/dist/providers/ufi-himi/prohibitions.d.ts +62 -0
- package/dist/providers/ufi-himi/prohibitions.js +88 -0
- package/dist/providers/ufi-himi/provider.d.ts +41 -0
- package/dist/providers/ufi-himi/provider.js +204 -0
- package/dist/providers/ufi-himi/qualcomm-evidence.d.ts +32 -0
- package/dist/providers/ufi-himi/qualcomm-evidence.js +51 -0
- package/dist/providers/ufi-himi/session.d.ts +46 -0
- package/dist/providers/ufi-himi/session.js +92 -0
- package/dist/providers/ufi-himi/transport.d.ts +29 -0
- package/dist/providers/ufi-himi/transport.js +25 -0
- package/dist/providers/zte-goform/index.d.ts +2 -0
- package/dist/providers/zte-goform/index.js +2 -0
- package/dist/providers/zte-goform/provider.d.ts +51 -0
- package/dist/providers/zte-goform/provider.js +101 -0
- package/dist/providers/zte-goform/session.d.ts +17 -0
- package/dist/providers/zte-goform/session.js +133 -0
- package/dist/providers/zte-goform/transport.d.ts +16 -0
- package/dist/providers/zte-goform/transport.js +1 -0
- package/dist/radio/band-truth.d.ts +50 -0
- package/dist/radio/band-truth.js +92 -0
- package/dist/radio/index.d.ts +3 -0
- package/dist/radio/index.js +10 -0
- package/dist/radio/mode-combinations.d.ts +78 -0
- package/dist/radio/mode-combinations.js +198 -0
- package/dist/radio/mode-truth.d.ts +67 -0
- package/dist/radio/mode-truth.js +112 -0
- package/dist/redact.d.ts +15 -0
- package/dist/redact.js +189 -0
- package/dist/safety/composition-root.d.ts +28 -0
- package/dist/safety/composition-root.js +65 -0
- package/dist/safety/flock-resource-ownership.d.ts +11 -0
- package/dist/safety/flock-resource-ownership.js +151 -0
- package/dist/safety/index.d.ts +2 -0
- package/dist/safety/index.js +2 -0
- package/dist/sms/dbus-messaging.d.ts +17 -0
- package/dist/sms/dbus-messaging.js +185 -0
- package/dist/sms/inbox-store.d.ts +10 -0
- package/dist/sms/inbox-store.js +82 -0
- package/dist/sms/index.d.ts +4 -0
- package/dist/sms/index.js +10 -0
- package/dist/sms/mmcli-parse.d.ts +54 -0
- package/dist/sms/mmcli-parse.js +224 -0
- package/dist/sms/normalize.d.ts +42 -0
- package/dist/sms/normalize.js +95 -0
- package/dist/testing/domain-fakes.d.ts +58 -0
- package/dist/testing/domain-fakes.js +98 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +17 -0
- package/dist/testing/provider-fakes.d.ts +45 -0
- package/dist/testing/provider-fakes.js +64 -0
- package/dist/transport/calls.d.ts +9 -0
- package/dist/transport/calls.js +88 -0
- package/dist/transport/codec.d.ts +3 -0
- package/dist/transport/codec.js +207 -0
- package/dist/transport/dbus-native.d.ts +57 -0
- package/dist/transport/dbus-native.js +17 -0
- package/dist/transport/errors.d.ts +21 -0
- package/{src/transport/errors.ts → dist/transport/errors.js} +34 -46
- package/dist/transport/index.d.ts +4 -0
- package/dist/transport/index.js +9 -0
- package/dist/transport/signals.d.ts +15 -0
- package/dist/transport/signals.js +123 -0
- package/dist/transport/signature.d.ts +7 -0
- package/dist/transport/signature.js +94 -0
- package/dist/transport/transport.d.ts +2 -0
- package/dist/transport/transport.js +202 -0
- package/dist/transport/types.d.ts +61 -0
- package/dist/transport/types.js +19 -0
- package/dist/usb-mode/catalog-schema.d.ts +139 -0
- package/dist/usb-mode/catalog-schema.js +97 -0
- package/dist/usb-mode/catalog.d.ts +21 -0
- package/{src/usb-mode/catalog.ts → dist/usb-mode/catalog.js} +10 -32
- package/dist/usb-mode/certified-catalog.json +67 -0
- package/dist/usb-mode/index.d.ts +5 -0
- package/dist/usb-mode/index.js +15 -0
- package/dist/usb-mode/ingestion.d.ts +111 -0
- package/dist/usb-mode/ingestion.js +187 -0
- package/dist/usb-mode/promotion-review.d.ts +21 -0
- package/dist/usb-mode/promotion-review.js +87 -0
- package/dist/usb-mode/usb-devices-parse.d.ts +36 -0
- package/dist/usb-mode/usb-devices-parse.js +157 -0
- package/dist/ussd/calls.d.ts +32 -0
- package/dist/ussd/calls.js +96 -0
- package/dist/ussd/index.d.ts +5 -0
- package/dist/ussd/index.js +12 -0
- package/dist/ussd/mm-ussd.d.ts +37 -0
- package/dist/ussd/mm-ussd.js +205 -0
- package/dist/ussd/refusal.d.ts +53 -0
- package/dist/ussd/refusal.js +154 -0
- package/dist/ussd/registration.d.ts +20 -0
- package/dist/ussd/registration.js +101 -0
- package/dist/ussd/session.d.ts +84 -0
- package/dist/ussd/session.js +163 -0
- package/package.json +38 -4
- package/src/backend/at-lease.test.ts +0 -106
- package/src/backend/at-lease.ts +0 -158
- package/src/backend/cell-info.test.ts +0 -154
- package/src/backend/cell-info.ts +0 -160
- package/src/backend/device-classifier.test.ts +0 -168
- package/src/backend/device-classifier.ts +0 -248
- package/src/backend/enrichment.ts +0 -96
- package/src/backend/features.test.ts +0 -162
- package/src/backend/features.ts +0 -179
- package/src/backend/identity-ladder.test.ts +0 -117
- package/src/backend/identity-ladder.ts +0 -221
- package/src/backend/identity-registry.test.ts +0 -89
- package/src/backend/identity-registry.ts +0 -151
- package/src/backend/index.ts +0 -221
- package/src/backend/lifecycle-interlock.ts +0 -38
- package/src/backend/managed-objects.ts +0 -108
- package/src/backend/mapping.ts +0 -160
- package/src/backend/mm-backend.ts +0 -191
- package/src/backend/mm-mutations.ts +0 -228
- package/src/backend/modem-actor.test.ts +0 -95
- package/src/backend/modem-actor.ts +0 -112
- package/src/backend/nm-auto-apn.ts +0 -161
- package/src/backend/nm-gsm-fields.ts +0 -122
- package/src/backend/nmcli-nm-port.ts +0 -228
- package/src/backend/nmcli-runner.ts +0 -52
- package/src/backend/observer.ts +0 -297
- package/src/backend/power-contract.test.ts +0 -40
- package/src/backend/power-contract.ts +0 -83
- package/src/backend/recovery-attribution.test.ts +0 -102
- package/src/backend/recovery-attribution.ts +0 -86
- package/src/backend/recovery-budget.test.ts +0 -64
- package/src/backend/recovery-budget.ts +0 -84
- package/src/backend/recovery-ladder.test.ts +0 -257
- package/src/backend/recovery-ladder.ts +0 -249
- package/src/backend/router-ethernet.test.ts +0 -71
- package/src/backend/router-ethernet.ts +0 -90
- package/src/backend/row-store.ts +0 -105
- package/src/backend/signal-setup.ts +0 -112
- package/src/backend/sim-unlock.ts +0 -193
- package/src/backend/transition-preconditions.ts +0 -149
- package/src/backend/usage/accounting.test.ts +0 -147
- package/src/backend/usage/accounting.ts +0 -123
- package/src/backend/usage/billing-cycle.test.ts +0 -62
- package/src/backend/usage/billing-cycle.ts +0 -45
- package/src/backend/usage/index.ts +0 -37
- package/src/backend/usage/proc-net-dev.test.ts +0 -56
- package/src/backend/usage/sampler.test.ts +0 -219
- package/src/backend/usage/sampler.ts +0 -228
- package/src/backend/usage/store.test.ts +0 -148
- package/src/backend/usage/store.ts +0 -177
- package/src/backend/usb-enumerator.test.ts +0 -87
- package/src/backend/usb-enumerator.ts +0 -181
- package/src/backend/usb-mode-transition.test.ts +0 -323
- package/src/backend/usb-mode-transition.ts +0 -253
- package/src/domain/brand.ts +0 -29
- package/src/domain/errors.ts +0 -77
- package/src/domain/guards.test.ts +0 -218
- package/src/domain/guards.ts +0 -144
- package/src/domain/identity.test.ts +0 -83
- package/src/domain/identity.ts +0 -165
- package/src/domain/index.ts +0 -12
- package/src/domain/snapshot.test.ts +0 -266
- package/src/domain/snapshot.ts +0 -120
- package/src/index.test.ts +0 -6
- package/src/index.ts +0 -15
- package/src/ports/README.md +0 -61
- package/src/ports/forbidden-surface.test.ts +0 -241
- package/src/ports/modem-manager.ts +0 -72
- package/src/ports/network-manager.ts +0 -87
- package/src/ports/ops.ts +0 -60
- package/src/ports/ops.type-test.ts +0 -39
- package/src/ports/receipts.test.ts +0 -153
- package/src/ports/reconcile.test.ts +0 -152
- package/src/ports/reconcile.ts +0 -338
- package/src/ports/router.ts +0 -29
- package/src/redact.test.ts +0 -82
- package/src/redact.ts +0 -73
- package/src/transport/README.md +0 -65
- package/src/transport/calls.ts +0 -113
- package/src/transport/characterization.test.ts +0 -260
- package/src/transport/codec.test.ts +0 -118
- package/src/transport/codec.ts +0 -240
- package/src/transport/conformance-python.test.ts +0 -152
- package/src/transport/conformance-same-lib.test.ts +0 -115
- package/src/transport/dbus-native-lib.d.ts +0 -19
- package/src/transport/dbus-native.ts +0 -85
- package/src/transport/index.ts +0 -30
- package/src/transport/no-library-leak.test.ts +0 -61
- package/src/transport/reliability.test.ts +0 -173
- package/src/transport/signals.ts +0 -150
- package/src/transport/signature.ts +0 -110
- package/src/transport/test-support/fake-service.ts +0 -168
- package/src/transport/test-support/independent-producer.py +0 -110
- package/src/transport/test-support/private-bus.ts +0 -66
- package/src/transport/transport.ts +0 -250
- package/src/transport/types.ts +0 -118
- package/src/usb-mode/catalog-schema.test.ts +0 -181
- package/src/usb-mode/catalog-schema.ts +0 -113
- package/src/usb-mode/certified-catalog.json +0 -67
- package/src/usb-mode/index.ts +0 -27
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// The adversarial accounting matrix — pure, deterministic proofs that per-slot usage
|
|
2
|
-
// is attributed correctly across remaps, swaps, reuse, resets, pauses, and rollovers.
|
|
3
|
-
|
|
4
|
-
import { describe, expect, test } from 'bun:test';
|
|
5
|
-
import { type IdentityConfidence, logicalSlotId } from '../../domain';
|
|
6
|
-
import { applySample, type BaselineKey, type SlotAccount } from './accounting';
|
|
7
|
-
|
|
8
|
-
const SLOT_A = logicalSlotId('slot-a');
|
|
9
|
-
const SLOT_B = logicalSlotId('slot-b');
|
|
10
|
-
const SLOT_C = logicalSlotId('slot-c');
|
|
11
|
-
const BOOT = 'boot-uuid-1';
|
|
12
|
-
|
|
13
|
-
interface Step {
|
|
14
|
-
readonly slot: string;
|
|
15
|
-
readonly gen: number;
|
|
16
|
-
readonly ifname: string;
|
|
17
|
-
readonly current: number;
|
|
18
|
-
readonly confidence?: IdentityConfidence;
|
|
19
|
-
readonly cycleStartMs?: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function key(slot: string, gen: number, ifname: string): BaselineKey {
|
|
23
|
-
return { logicalSlotId: slot, mappingGeneration: gen, ifname, bootId: BOOT };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function step(prior: SlotAccount | undefined, s: Step): SlotAccount {
|
|
27
|
-
return applySample(prior, {
|
|
28
|
-
key: key(s.slot, s.gen, s.ifname),
|
|
29
|
-
current: s.current,
|
|
30
|
-
confidence: s.confidence ?? 'high',
|
|
31
|
-
cycleStartMs: s.cycleStartMs ?? 1000,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
describe('applySample — two modems tracked independently', () => {
|
|
36
|
-
test('separate slots never cross-contaminate', () => {
|
|
37
|
-
let a = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 100 });
|
|
38
|
-
let b = step(undefined, { slot: SLOT_B, gen: 0, ifname: 'wwan1', current: 5000 });
|
|
39
|
-
a = step(a, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 300 });
|
|
40
|
-
b = step(b, { slot: SLOT_B, gen: 0, ifname: 'wwan1', current: 5001 });
|
|
41
|
-
expect(a.cycleBytes).toBe(200);
|
|
42
|
-
expect(b.cycleBytes).toBe(1);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('applySample — A/B ifname swap follows the slot, not the interface', () => {
|
|
47
|
-
test('each slot keeps its own total across a swap and re-baselines zero-delta', () => {
|
|
48
|
-
// Prime: A on wwan0, B on wwan1.
|
|
49
|
-
let a = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 100 });
|
|
50
|
-
let b = step(undefined, { slot: SLOT_B, gen: 0, ifname: 'wwan1', current: 1000 });
|
|
51
|
-
a = step(a, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 200 });
|
|
52
|
-
b = step(b, { slot: SLOT_B, gen: 0, ifname: 'wwan1', current: 1100 });
|
|
53
|
-
expect(a.cycleBytes).toBe(100);
|
|
54
|
-
expect(b.cycleBytes).toBe(100);
|
|
55
|
-
|
|
56
|
-
// Swap: A now maps to wwan1, B to wwan0 (mapping generation bumps for both).
|
|
57
|
-
// First post-swap sample must be zero-delta despite the large counter change.
|
|
58
|
-
a = step(a, { slot: SLOT_A, gen: 1, ifname: 'wwan1', current: 1100 });
|
|
59
|
-
b = step(b, { slot: SLOT_B, gen: 1, ifname: 'wwan0', current: 200 });
|
|
60
|
-
expect(a.cycleBytes).toBe(100);
|
|
61
|
-
expect(b.cycleBytes).toBe(100);
|
|
62
|
-
|
|
63
|
-
// Subsequent growth attributes to the correct slot on its new interface.
|
|
64
|
-
a = step(a, { slot: SLOT_A, gen: 1, ifname: 'wwan1', current: 1150 });
|
|
65
|
-
b = step(b, { slot: SLOT_B, gen: 1, ifname: 'wwan0', current: 260 });
|
|
66
|
-
expect(a.cycleBytes).toBe(150);
|
|
67
|
-
expect(b.cycleBytes).toBe(160);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('applySample — old ifname reused by a different slot (no bleed)', () => {
|
|
72
|
-
test('a new slot inheriting an old interface starts from zero', () => {
|
|
73
|
-
let a = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 100 });
|
|
74
|
-
a = step(a, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 500 });
|
|
75
|
-
expect(a.cycleBytes).toBe(400);
|
|
76
|
-
|
|
77
|
-
// Slot C now occupies wwan0. Its own account starts fresh (zero-delta baseline).
|
|
78
|
-
let c = step(undefined, { slot: SLOT_C, gen: 0, ifname: 'wwan0', current: 500 });
|
|
79
|
-
c = step(c, { slot: SLOT_C, gen: 0, ifname: 'wwan0', current: 700 });
|
|
80
|
-
expect(c.cycleBytes).toBe(200);
|
|
81
|
-
// A's total is untouched — no bleed either direction.
|
|
82
|
-
expect(a.cycleBytes).toBe(400);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('applySample — rename-first-sample is zero-delta', () => {
|
|
87
|
-
test('the first sample after a remap never reports a spurious jump', () => {
|
|
88
|
-
let s = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 100 });
|
|
89
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 200 });
|
|
90
|
-
expect(s.cycleBytes).toBe(100);
|
|
91
|
-
// Rename wwan0 → wwan5 with a huge counter: must NOT attribute 9M.
|
|
92
|
-
s = step(s, { slot: SLOT_A, gen: 1, ifname: 'wwan5', current: 9_000_000 });
|
|
93
|
-
expect(s.cycleBytes).toBe(100);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('applySample — reset-then-positive', () => {
|
|
98
|
-
test('a counter reset clamps to zero, then normal increases resume', () => {
|
|
99
|
-
let s = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 1000 });
|
|
100
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 1500 });
|
|
101
|
-
expect(s.cycleBytes).toBe(500);
|
|
102
|
-
// Interface recreated: counter drops to 50 (decrease) → clamp + rebase.
|
|
103
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 50 });
|
|
104
|
-
expect(s.cycleBytes).toBe(500);
|
|
105
|
-
// Growth from the rebased baseline is tracked again.
|
|
106
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 250 });
|
|
107
|
-
expect(s.cycleBytes).toBe(700);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('a decrease never produces a negative delta', () => {
|
|
111
|
-
let s = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 800 });
|
|
112
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 300 });
|
|
113
|
-
expect(s.cycleBytes).toBe(0);
|
|
114
|
-
expect(s.cycleBytes).toBeGreaterThanOrEqual(0);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
describe('applySample — ambiguous identity pauses sampling', () => {
|
|
119
|
-
test('low confidence attributes nothing and re-baselines zero-delta on resume', () => {
|
|
120
|
-
let s = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 100 });
|
|
121
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 300 });
|
|
122
|
-
expect(s.cycleBytes).toBe(200);
|
|
123
|
-
// Identity turns ambiguous → paused; the counter keeps climbing unattributed.
|
|
124
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 9999, confidence: 'low' });
|
|
125
|
-
expect(s.paused).toBe(true);
|
|
126
|
-
expect(s.cycleBytes).toBe(200);
|
|
127
|
-
// Confidence returns: resume is zero-delta, so the paused-window bytes are NOT
|
|
128
|
-
// back-attributed; only growth after resume counts.
|
|
129
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 9999 });
|
|
130
|
-
expect(s.paused).toBe(false);
|
|
131
|
-
expect(s.cycleBytes).toBe(200);
|
|
132
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 10_099 });
|
|
133
|
-
expect(s.cycleBytes).toBe(300);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('applySample — cycle rollover resets the per-cycle total', () => {
|
|
138
|
-
test('crossing into a newer cycle zeroes cycleBytes but keeps the baseline', () => {
|
|
139
|
-
let s = step(undefined, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 100 });
|
|
140
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 600 });
|
|
141
|
-
expect(s.cycleBytes).toBe(500);
|
|
142
|
-
// New cycle boundary — cycleBytes resets, counter continuity preserved.
|
|
143
|
-
s = step(s, { slot: SLOT_A, gen: 0, ifname: 'wwan0', current: 650, cycleStartMs: 2000 });
|
|
144
|
-
expect(s.cycleStartMs).toBe(2000);
|
|
145
|
-
expect(s.cycleBytes).toBe(50);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// The pure usage-accounting reducer — the heart of the sampler.
|
|
2
|
-
//
|
|
3
|
-
// For each logical slot we keep a per-cycle byte total plus a BASELINE: the last
|
|
4
|
-
// observed cumulative counter value under a specific key. The key is the composite
|
|
5
|
-
// `{logicalSlotId, mappingGeneration, ifname, bootId}`. The rules, all encoded here
|
|
6
|
-
// with zero I/O so they can be exhaustively unit-tested:
|
|
7
|
-
//
|
|
8
|
-
// - REMAP (any key field changes — e.g. the ifname-to-slot mapping bumped
|
|
9
|
-
// `mappingGeneration`, or a reboot changed `bootId`): rebaseline with a
|
|
10
|
-
// ZERO-DELTA sample. We start counting fresh from the current cumulative value
|
|
11
|
-
// and attribute nothing for that first sample — never a spurious jump.
|
|
12
|
-
// - SAME-KEY DECREASE (the cumulative counter went DOWN — interface re-created /
|
|
13
|
-
// counter reset without a reported remap): CLAMP the negative delta to zero and
|
|
14
|
-
// REBASE the baseline to the new lower value. Never report negative usage.
|
|
15
|
-
// - LOW CONFIDENCE (ambiguous identity, A3.2 ladder): sampling is PAUSED. We drop
|
|
16
|
-
// the baseline and attribute nothing; on resume the next sample is zero-delta so
|
|
17
|
-
// bytes moved during the ambiguous window are never mis-attributed.
|
|
18
|
-
// - CYCLE ROLLOVER (`now` crossed into a new billing cycle): the per-cycle total
|
|
19
|
-
// resets to zero. The baseline is kept — the kernel counter is continuous across
|
|
20
|
-
// a billing boundary; only OUR accounting window resets.
|
|
21
|
-
|
|
22
|
-
import type { IdentityConfidence, LogicalSlotId } from '../../domain';
|
|
23
|
-
|
|
24
|
-
/** The composite baseline key. A change in ANY field is a remap (zero-delta rebase). */
|
|
25
|
-
export interface BaselineKey {
|
|
26
|
-
readonly logicalSlotId: string;
|
|
27
|
-
readonly mappingGeneration: number;
|
|
28
|
-
readonly ifname: string;
|
|
29
|
-
readonly bootId: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Per-slot accounting state. `key`/`lastObserved` are unset before the first sample. */
|
|
33
|
-
export interface SlotAccount {
|
|
34
|
-
/** Bytes attributed to this slot within the current cycle. */
|
|
35
|
-
readonly cycleBytes: number;
|
|
36
|
-
/** UTC start of the cycle `cycleBytes` is accruing into. */
|
|
37
|
-
readonly cycleStartMs: number;
|
|
38
|
-
/** True when the last observation was low-confidence and sampling is paused. */
|
|
39
|
-
readonly paused: boolean;
|
|
40
|
-
/** The key the baseline was captured under (undefined = no baseline yet). */
|
|
41
|
-
readonly key?: BaselineKey;
|
|
42
|
-
/** The cumulative counter value at the last accepted sample. */
|
|
43
|
-
readonly lastObserved?: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** One observation fed to the reducer for a single slot in one sampling pass. */
|
|
47
|
-
export interface SampleInput {
|
|
48
|
-
readonly key: BaselineKey;
|
|
49
|
-
/** The current cumulative rx+tx counter for the slot's interface. */
|
|
50
|
-
readonly current: number;
|
|
51
|
-
readonly confidence: IdentityConfidence;
|
|
52
|
-
/** The UTC start of the slot's active cycle (from `cycleStart`). */
|
|
53
|
-
readonly cycleStartMs: number;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** A fresh account for a slot first seen in `cycleStartMs`. */
|
|
57
|
-
export function initialAccount(cycleStartMs: number): SlotAccount {
|
|
58
|
-
return { cycleBytes: 0, cycleStartMs, paused: false };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function sameKey(a: BaselineKey, b: BaselineKey): boolean {
|
|
62
|
-
return (
|
|
63
|
-
a.logicalSlotId === b.logicalSlotId &&
|
|
64
|
-
a.mappingGeneration === b.mappingGeneration &&
|
|
65
|
-
a.ifname === b.ifname &&
|
|
66
|
-
a.bootId === b.bootId
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Apply a cycle rollover: if we crossed into a newer cycle, zero the per-cycle total. */
|
|
71
|
-
function rollCycle(account: SlotAccount, cycleStartMs: number): SlotAccount {
|
|
72
|
-
if (cycleStartMs > account.cycleStartMs) {
|
|
73
|
-
return { ...account, cycleBytes: 0, cycleStartMs };
|
|
74
|
-
}
|
|
75
|
-
return account;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Fold one observation into a slot's account, returning the NEXT account. Pure —
|
|
80
|
-
* no clock, no I/O; the caller supplies `current`, `confidence` and `cycleStartMs`.
|
|
81
|
-
*/
|
|
82
|
-
export function applySample(prior: SlotAccount | undefined, input: SampleInput): SlotAccount {
|
|
83
|
-
const base = rollCycle(prior ?? initialAccount(input.cycleStartMs), input.cycleStartMs);
|
|
84
|
-
|
|
85
|
-
// Ambiguous identity → pause: attribute nothing and drop the baseline so the
|
|
86
|
-
// next confident sample re-baselines zero-delta (no back-attribution).
|
|
87
|
-
if (input.confidence === 'low') {
|
|
88
|
-
return { cycleBytes: base.cycleBytes, cycleStartMs: base.cycleStartMs, paused: true };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Remap, first-ever sample, or resuming from a pause → zero-delta rebaseline.
|
|
92
|
-
if (base.paused || base.key === undefined || base.lastObserved === undefined) {
|
|
93
|
-
return { ...base, paused: false, key: input.key, lastObserved: input.current };
|
|
94
|
-
}
|
|
95
|
-
if (!sameKey(base.key, input.key)) {
|
|
96
|
-
return { ...base, paused: false, key: input.key, lastObserved: input.current };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Same key: a decrease is a counter reset → clamp the negative delta and rebase.
|
|
100
|
-
if (input.current < base.lastObserved) {
|
|
101
|
-
return { ...base, paused: false, key: input.key, lastObserved: input.current };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Normal case: attribute the non-negative delta and advance the baseline.
|
|
105
|
-
const delta = input.current - base.lastObserved;
|
|
106
|
-
return {
|
|
107
|
-
...base,
|
|
108
|
-
paused: false,
|
|
109
|
-
key: input.key,
|
|
110
|
-
lastObserved: input.current,
|
|
111
|
-
cycleBytes: base.cycleBytes + delta,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Convenience constructor for a `BaselineKey` from its parts. */
|
|
116
|
-
export function baselineKey(
|
|
117
|
-
logicalSlotId: LogicalSlotId,
|
|
118
|
-
mappingGeneration: number,
|
|
119
|
-
ifname: string,
|
|
120
|
-
bootId: string,
|
|
121
|
-
): BaselineKey {
|
|
122
|
-
return { logicalSlotId, mappingGeneration, ifname, bootId };
|
|
123
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
// UTC billing-cycle math — month-length clamping (cycleDay 31 → Feb 28/29) and the
|
|
2
|
-
// before/after-boundary cycle-start selection.
|
|
3
|
-
|
|
4
|
-
import { describe, expect, test } from 'bun:test';
|
|
5
|
-
import { type EpochMillis, epochMillis } from '../../domain';
|
|
6
|
-
import { clampCycleDay, cycleStart, daysInMonth } from './billing-cycle';
|
|
7
|
-
|
|
8
|
-
const utc = (y: number, m: number, d: number, h = 0): EpochMillis =>
|
|
9
|
-
epochMillis(Date.UTC(y, m, d, h));
|
|
10
|
-
|
|
11
|
-
describe('daysInMonth', () => {
|
|
12
|
-
test('February is 28 days in a common year, 29 in a leap year', () => {
|
|
13
|
-
expect(daysInMonth(2023, 1)).toBe(28);
|
|
14
|
-
expect(daysInMonth(2024, 1)).toBe(29); // 2024 is a leap year
|
|
15
|
-
expect(daysInMonth(2100, 1)).toBe(28); // century non-leap
|
|
16
|
-
expect(daysInMonth(2000, 1)).toBe(29); // 400-divisible leap
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('30- and 31-day months', () => {
|
|
20
|
-
expect(daysInMonth(2024, 3)).toBe(30); // April
|
|
21
|
-
expect(daysInMonth(2024, 0)).toBe(31); // January
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('clampCycleDay', () => {
|
|
26
|
-
test('cycleDay 31 clamps to the last day of a short month', () => {
|
|
27
|
-
expect(clampCycleDay(31, 2023, 1)).toBe(28); // Feb non-leap
|
|
28
|
-
expect(clampCycleDay(31, 2024, 1)).toBe(29); // Feb leap
|
|
29
|
-
expect(clampCycleDay(31, 2024, 3)).toBe(30); // April
|
|
30
|
-
expect(clampCycleDay(31, 2024, 0)).toBe(31); // January — no clamp
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('a valid in-range day is unchanged; a floor of 1 is enforced', () => {
|
|
34
|
-
expect(clampCycleDay(15, 2024, 5)).toBe(15);
|
|
35
|
-
expect(clampCycleDay(0, 2024, 5)).toBe(1);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('cycleStart — month-length clamp with before/after selection', () => {
|
|
40
|
-
test('cycleDay 31 in February resolves to the clamped Feb boundary', () => {
|
|
41
|
-
// 2023-02-15 with cycleDay 31 → cycle started 2023-01-31 (Feb boundary Feb 28
|
|
42
|
-
// is still ahead of the 15th).
|
|
43
|
-
expect(cycleStart(epochMillis(utc(2023, 1, 15)), 31)).toBe(utc(2023, 0, 31));
|
|
44
|
-
// 2023-03-01 with cycleDay 31 → the active cycle began at clamped Feb 28.
|
|
45
|
-
expect(cycleStart(epochMillis(utc(2023, 2, 1)), 31)).toBe(utc(2023, 1, 28));
|
|
46
|
-
// Leap year: 2024-03-01 → Feb 29.
|
|
47
|
-
expect(cycleStart(epochMillis(utc(2024, 2, 1)), 31)).toBe(utc(2024, 1, 29));
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('now exactly on the boundary starts a new cycle', () => {
|
|
51
|
-
expect(cycleStart(epochMillis(utc(2024, 5, 10)), 10)).toBe(utc(2024, 5, 10));
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('now before this month boundary rolls back to the previous month', () => {
|
|
55
|
-
// cycleDay 20, now is the 5th → cycle began on the 20th of the prior month.
|
|
56
|
-
expect(cycleStart(epochMillis(utc(2024, 6, 5)), 20)).toBe(utc(2024, 5, 20));
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test('January rollback wraps to December of the prior year', () => {
|
|
60
|
-
expect(cycleStart(epochMillis(utc(2024, 0, 5)), 20)).toBe(utc(2023, 11, 20));
|
|
61
|
-
});
|
|
62
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// UTC billing-cycle computation with month-length clamping.
|
|
2
|
-
//
|
|
3
|
-
// A usage cycle resets on a configured day of the month (`cycleDay`, 1–31) in UTC.
|
|
4
|
-
// Months are not all the same length, so a `cycleDay` past the end of a short month
|
|
5
|
-
// must clamp to that month's LAST day rather than rolling into the next month or
|
|
6
|
-
// throwing: `cycleDay: 31` resolves to Feb 28 (or Feb 29 in a leap year), Apr 30,
|
|
7
|
-
// etc. All arithmetic is UTC — the device clock's local zone never shifts a cycle.
|
|
8
|
-
|
|
9
|
-
import type { EpochMillis } from '../../domain';
|
|
10
|
-
|
|
11
|
-
/** Days in a given UTC month. `month` is 0-based (0 = January). Handles leap Feb. */
|
|
12
|
-
export function daysInMonth(year: number, month: number): number {
|
|
13
|
-
// Day 0 of the next month is the last day of this month; UTC avoids DST drift.
|
|
14
|
-
return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Clamp a requested cycle day to the last valid day of the given month. */
|
|
18
|
-
export function clampCycleDay(cycleDay: number, year: number, month: number): number {
|
|
19
|
-
const floor = Math.max(1, Math.trunc(cycleDay));
|
|
20
|
-
return Math.min(floor, daysInMonth(year, month));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** The UTC epoch-ms of the cycle boundary in a specific month (clamped). */
|
|
24
|
-
function boundaryFor(cycleDay: number, year: number, month: number): number {
|
|
25
|
-
return Date.UTC(year, month, clampCycleDay(cycleDay, year, month));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The UTC start (`EpochMillis`) of the cycle that `now` falls in for a given
|
|
30
|
-
* `cycleDay`. If `now` is before this month's (clamped) boundary the active cycle
|
|
31
|
-
* began on the previous month's boundary; otherwise it began on this month's.
|
|
32
|
-
*/
|
|
33
|
-
export function cycleStart(now: EpochMillis, cycleDay: number): EpochMillis {
|
|
34
|
-
const at = new Date(now);
|
|
35
|
-
const year = at.getUTCFullYear();
|
|
36
|
-
const month = at.getUTCMonth();
|
|
37
|
-
const thisBoundary = boundaryFor(cycleDay, year, month);
|
|
38
|
-
if (now >= thisBoundary) {
|
|
39
|
-
return thisBoundary as EpochMillis;
|
|
40
|
-
}
|
|
41
|
-
// Roll back one month (December wraps to the prior year), re-clamping there.
|
|
42
|
-
const prevMonth = month === 0 ? 11 : month - 1;
|
|
43
|
-
const prevYear = month === 0 ? year - 1 : year;
|
|
44
|
-
return boundaryFor(cycleDay, prevYear, prevMonth) as EpochMillis;
|
|
45
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// Data-usage sampler — internal all-interface sampler over `/proc/net/dev`
|
|
2
|
-
// CUMULATIVE counters (A4.3). Public surface consumed by the A6.1 bench CLI `usage`
|
|
3
|
-
// command (via `UsageSnapshot`) and the composition root that wires the sampler.
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
applySample,
|
|
7
|
-
type BaselineKey,
|
|
8
|
-
baselineKey,
|
|
9
|
-
initialAccount,
|
|
10
|
-
type SampleInput,
|
|
11
|
-
type SlotAccount,
|
|
12
|
-
} from './accounting';
|
|
13
|
-
export { clampCycleDay, cycleStart, daysInMonth } from './billing-cycle';
|
|
14
|
-
export { readBootId } from './boot-id';
|
|
15
|
-
export {
|
|
16
|
-
type CounterSource,
|
|
17
|
-
parseProcNetDev,
|
|
18
|
-
procNetDevCounterSource,
|
|
19
|
-
} from './proc-net-dev';
|
|
20
|
-
export {
|
|
21
|
-
createUsageSampler,
|
|
22
|
-
type SlotUsageSnapshot,
|
|
23
|
-
type UsageObservation,
|
|
24
|
-
UsageSampler,
|
|
25
|
-
type UsageSamplerOptions,
|
|
26
|
-
type UsageSnapshot,
|
|
27
|
-
} from './sampler';
|
|
28
|
-
export {
|
|
29
|
-
createUsageFileStore,
|
|
30
|
-
type PersistedSlot,
|
|
31
|
-
type PersistedUsage,
|
|
32
|
-
USAGE_SCHEMA_VERSION,
|
|
33
|
-
type UsageFileStoreOptions,
|
|
34
|
-
type UsageLogEvent,
|
|
35
|
-
type UsageLogger,
|
|
36
|
-
type UsageStore,
|
|
37
|
-
} from './store';
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// `/proc/net/dev` parser — proves rx+tx cumulative totals over the real fixed-column
|
|
2
|
-
// format, header skipping, and fail-soft handling of malformed rows.
|
|
3
|
-
|
|
4
|
-
import { describe, expect, test } from 'bun:test';
|
|
5
|
-
import { parseProcNetDev } from './proc-net-dev';
|
|
6
|
-
|
|
7
|
-
// A real capture (columns: rx bytes packets errs drop fifo frame compressed multicast
|
|
8
|
-
// | tx bytes packets errs drop fifo colls carrier compressed).
|
|
9
|
-
const REAL = `Inter-| Receive | Transmit
|
|
10
|
-
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
|
|
11
|
-
lo: 160183007830 18519510 0 0 0 0 0 0 160183007830 18519510 0 0 0 0 0 0
|
|
12
|
-
eno2: 88166142004 86575608 0 0 48 0 0 146660 25843393633 48414413 0 3 0 0 0 0
|
|
13
|
-
wlan0: 44865976 194892 0 0 0 0 0 0 5698312 36057 0 23 0 0 0 0
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
describe('parseProcNetDev', () => {
|
|
17
|
-
test('reads rx+tx cumulative bytes for each interface, skipping the 2-line header', () => {
|
|
18
|
-
const counters = parseProcNetDev(REAL);
|
|
19
|
-
expect(counters.size).toBe(3);
|
|
20
|
-
// lo: 160183007830 (rx) + 160183007830 (tx).
|
|
21
|
-
expect(counters.get('lo')).toBe(160183007830 + 160183007830);
|
|
22
|
-
// eno2: rx 88166142004 + tx 25843393633.
|
|
23
|
-
expect(counters.get('eno2')).toBe(88166142004 + 25843393633);
|
|
24
|
-
// wlan0: rx 44865976 + tx 5698312.
|
|
25
|
-
expect(counters.get('wlan0')).toBe(44865976 + 5698312);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('handles bridge-style names with no leading space and long names', () => {
|
|
29
|
-
const text = `h1
|
|
30
|
-
h2
|
|
31
|
-
br-d739ee545df1: 575402021 542380 0 0 0 0 0 0 450821722 810015 0 4 0 0 0 0
|
|
32
|
-
docker0: 1750867165 1097738 0 0 0 0 0 0 5810268898 1237921 0 12223 0 0 0 0
|
|
33
|
-
`;
|
|
34
|
-
const counters = parseProcNetDev(text);
|
|
35
|
-
expect(counters.get('br-d739ee545df1')).toBe(575402021 + 450821722);
|
|
36
|
-
expect(counters.get('docker0')).toBe(1750867165 + 5810268898);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('ignores malformed / short rows without throwing', () => {
|
|
40
|
-
const text = `h1
|
|
41
|
-
h2
|
|
42
|
-
lo: 100 1 0 0 0 0 0 0 200 2 0 0 0 0 0 0
|
|
43
|
-
garbage-without-colon 1 2 3
|
|
44
|
-
short: 1 2 3
|
|
45
|
-
nan: x 1 0 0 0 0 0 0 y 2 0 0 0 0 0 0
|
|
46
|
-
`;
|
|
47
|
-
const counters = parseProcNetDev(text);
|
|
48
|
-
// Only the well-formed `lo` row survives.
|
|
49
|
-
expect(counters.size).toBe(1);
|
|
50
|
-
expect(counters.get('lo')).toBe(300);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('empty input yields an empty map', () => {
|
|
54
|
-
expect(parseProcNetDev('').size).toBe(0);
|
|
55
|
-
});
|
|
56
|
-
});
|