Skip to content

carelink-bridge v0.2.0

Latest

Choose a tag to compare

@NovaLux12 NovaLux12 released this 22 Jul 13:12
· 17 commits to main since this release
bc33d2f

Highlights

This is the first minor version bump since v0.1.0. Per the project's convention
(0.x: minor = phase, patch = fixes within a phase), v0.2.0 reflects a new
phase — security and reliability hardening — rather than a fix-level patch.

80 new tests added, all green on Linux (135 passed (15 files)). No
behavioural change is expected on a working account; the changes tighten
the existing 401-refresh, retry-loop, and token-write paths and surface
better signals on failure.

Test progression (v0.1.6 → v0.2.0)

 55  v0.1.6 baseline
 55 →  61  (+6)   Atomic 0600 logindata.json write
 61 →  67  (+6)   P0.1 mmol/L safety
 67 →  79  (+12)  P0.2 lastAlarm policy
 79 →  80  (+1)   forceRefresh successive-401 regression
 80 →  81  (+1)   P3 trend NONE -> Flat
 81 →  92  (+11)  NoAuth0SSOConfigurationError + selectAuth0ConfigUrl (6) + Discovery pinning (5)
 92 →  92  ( 0)   CARELINK_MAX_RETRY_DURATION removal
 92 → 110  (+18)  Refresh-failure classification
110 → 133  (+23)  Status-aware backoff helper (decideRetry unit tests)
133 → 135  (+2)   Status-aware backoff integration (429 Retry-After + 404 fail-fast)
135  final

Shipped

Added

  • Atomic 0600 logindata.json writewriteLoginDataAtomic opens the
    temp file with O_CREAT|O_EXCL|O_WRONLY and mode(0o600), fsyncs,
    then renames atomically. Closes the world-readable window between temp
    create and chmod that umask-022 boxes had. tightenLoginDataIfLoose runs
    on the loadLoginData read path so an older bridge with a pre-existing
    0644 file is closed without a one-shot migration step.
  • P0.1 mmol/L safetysrc/transform/index.ts detects
    bgunits/bgUnits of MMOL_L (with casing fallbacks) and converts
    sg to mg/dL via Math.round(sg * 18.0182). Asserted numerically:
    5.5 mmol/L → 99 mg/dL, 2.0 → 36, 22.2 → 400.
  • P0.2 lastAlarm policysrc/last-alarm.ts plus
    NightscoutLastAlarmAnnotation. CareLink alarms surface as
    devicestatus.last_alarm (code/datetime/text/severity). Priority-1
    codes hit console.warn always-on. No alarm relay to Nightscout
    /api/v1/treatments.json
    — verified by an absence-grep test over
    src/.
  • NoAuth0SSOConfigurationError + selectAuth0ConfigUrl — named
    error is grep-distinguishable in journald. The helper throws it on
    missing Auth0SSOConfiguration in the discovery entry, carrying
    diagnostic context (region, appVersion) for operators.
  • Discovery pinningDISCOVERY_APP_VERSION = 'android/3.6' and
    buildDiscoveryUrl(isUS) extracted into src/discovery.ts. Testable
    constants; future contributors can't silently regress the bridge to
    a no-Auth0 track (3.4 / 4.0).
  • Refresh-failure classificationisPermanentRefreshFailure
    predicate in src/refresh-failure.ts. Distinguishes permanent
    (HTTP 400 + invalid_grant / invalid_client) from recoverable
    (5xx, 429, transport). The catch in authenticate() is split so
    a successful refresh + write failure doesn't nuke the token.
  • Status-aware capped exponential backoff with jitter, honour
    Retry-After
    decideRetry in src/retry-policy.ts. Permanent
    4xx fail fast; 429 honours Retry-After (numeric or HTTP-date)
    capped; 5xx and transport errors retry with full-jitter backoff
    (capped). The pre-fix fixed 2s/4s/8s path is replaced.

Removed

  • CARELINK_MAX_RETRY_DURATION env, Config.maxRetryDuration
    field, CareLinkClientOptions.maxRetryDuration field, and
    DEFAULT_MAX_RETRY_DURATION constant
    — the option had no defined
    unit, the fetch loop never honoured it, and the fix-path is the
    status-aware policy above.

Verification

npx tsc --noEmit:    PASS
npm test -- --run:   135 passed (15 files), 0 failed, 0 skipped
npm run build:      clean emit to dist/ (dist/ is .gitignored)

Risk

  • Behavioural changes are bounded to the fetch retry loop and the
    refresh-token deletion decision. The two pre-existing 401-refresh
    regression tests (should force a token refresh after a 401 and succeed on retry, should refresh again on a 401 immediately after a successful refresh+401) are the canary — both still pass.
  • The 429 with Retry-After: 25 integration test is the load-bearing
    proof that the server-set delay is honoured.
  • The 404 fail-fast integration test is the load-bearing proof that
    the loop doesn't hammer a permanent-failure host.
  • The named-error class and discovery pinning are observation-only:
    no behaviour change for working accounts.

Notes

This is expected to be the last contribution in the current maintenance
window. The 780G-payload-fixture items (markers[] for treatments,
therapyAlgorithmState for auto-mode, limits[] schedule, multi-patient
fan-out, reservoirLevelPercent snap-points, NGP-tier alarm codes) remain
deferred until a real pump arrives (currently expected November 2026)
or another operator contributes sanitised fixtures. Project maintenance
continues passively — issue reports and security advisories are still
monitored.