Skip to content

Releases: NovaLux12/carelink-bridge

carelink-bridge v0.2.0

Choose a tag to compare

@NovaLux12 NovaLux12 released this 22 Jul 13:12
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.

v0.1.6 — doctor pre-flight check + discovery-version guard

Choose a tag to compare

@NovaLux12 NovaLux12 released this 19 Jul 22:02
6a6bd3d

Pre-pump operability, and a compatibility hardening from the public-config research.

Added

  • npm run doctor (#28) — a pre-flight self-check to run the moment a new pump pairs. Confirms .env is complete, decodes and reports your login token's validity/expiry, and checks that CareLink and Nightscout are both reachable with an accepted API_SECRET — without fetching pump data. One request each to two hosts, safe to run repeatedly; non-zero exit on failure so it can gate a deploy. First item of the v0.2.0 operability set (#8).

Changed

  • Discovery app-version pinned as a documented constant (#27). Live probing showed Medtronic's discovery endpoint returns a different config per app-version string — only android/3.6/3.7 carry the Auth0 SSO config this flow needs (3.4 and 4.0 return no-Auth0 tracks) — so bumping it to a "newer" number would silently break login. The failure now names the version string as the likely cause.

55/55 tests on Node 20 + 22. No new dependencies. Still no real-CareLink validation — that waits on the pump (#12).

v0.1.5 — server-reported username for data requests

Choose a tag to compare

@NovaLux12 NovaLux12 released this 19 Jul 18:27
2f36a0f

One fix from round 2 of the auth-flow research (findings), which validated the bridge's login-page scraping against Medtronic's live Auth0 Universal Login and cross-checked data fetching against nightscout-connect.

Fix

  • Data POST bodies now use the username CareLink reports from /users/me rather than CARELINK_USERNAME verbatim (#25). If you enter your email in .env while your CareLink username differs, previous versions sent the wrong identifier on every BLE/carepartner data request. Both reference implementations source the username from the server/token; the bridge now does too, with the configured value as fallback. A verbose-mode log notes when the two differ.

Research conclusions shipped as documentation (no code change)

  • Strategy 1 (automated login) assumptions validated against the live Auth0 New Universal Login page: field names, hidden state, action=default submit, and the form-action fallback all match. CAPTCHA is present but dormant (no active siteKey); wrong-credential string detection is untestable without a real failed login.
  • Both CareLink API families are alive; nightscout-connect uses the same patient-portal endpoints with plain Bearer auth — de-risking the endpoint-family watch item.
  • US SSO config verified structurally identical (own client_id/audience); v13 confirmed as current API generation; GB→EU mapping confirmed.

42/42 tests on Node 20 + 22. No new dependencies.

v0.1.4 — auth hardening from live-config research

Choose a tag to compare

@NovaLux12 NovaLux12 released this 19 Jul 18:19
ddc09ef

Two fixes from the 2026-07-19 auth-flow research session (full findings: #12 comment), which validated the implementation against Medtronic's live discovery/SSO/OpenID configs and the carelink-python-client reference.

Fixes

  • Force token refresh on 401/403 (#22, fixes #21). CareLink can invalidate a token before its exp claim — most commonly when the CareLink phone app logs into the same account. The bridge previously retried the dead token until natural expiry; it now refreshes and retries. Expiry margin widened 60s→600s to match the reference client.
  • Endpoint fallback chain now includes v13 (#23). Medtronic's app discovery config advertises the carepartner API at v13; the old hardcoded fallback list only handled v5/v6/v11. Fallbacks are now derived from a version list (13, 11, 6, 5) and degrade sanely for unknown future versions.

Research conclusions (no code change needed)

  • Medtronic completed migration to Auth0 for both US and EU; the bridge implements the correct (Auth0) flow with PKCE, which the tenant explicitly supports (S256).
  • Token refresh parameters and the primary BLE data endpoint match the live config and reference implementation.
  • Remaining validation requires a real account — watch items tracked in #12.

37/37 tests on Node 20 + 22. No new dependencies.

v0.1.3 — deployment artifacts + review fixes

Choose a tag to compare

@NovaLux12 NovaLux12 released this 19 Jul 18:03
6465818

Deployment artifacts (the v0.1.3 phase from ROADMAP.md)

  • deploy/systemd/carelink-bridge.service — hardened user-level systemd unit (#6)
  • deploy/install.sh — idempotent install/update script (#6)
  • deploy/nightscout-docker-compose.yml — Nightscout + MongoDB + cloudflared stack (#6)
  • deploy/README.md — full deployment runbook (#6)

Fixes from the 2026-07-19 full-repo review

  • Pump timezone offset now rounds to the nearest 15 minutes, not whole hours (#20, fixes #15). Previously, users in half/quarter-hour timezones (+05:30 India, +09:30 central Australia, +05:45 Nepal, −03:30 Newfoundland) had every SGV timestamp skewed by up to 30 minutes. ⚠️ Behaviour change: pump clocks off by more than 7.5 minutes are no longer silently rounded away — set the pump clock accurately.
  • systemd ReadWritePaths is now directory-level (#19, fixes #16). The previous per-file bind mounts would have silently blocked the stale-token recovery path (deleting logindata.json on refresh-token expiry). Needs on-host verification — see #16's checklist.
  • Version/docs sync (#18, fixes #17): package.json now matches the release tag, CONTRIBUTING's Node matrix matches CI (20/22), and a maintainer release checklist prevents recurrence.

Notes

  • No new dependencies. 33/33 tests passing on Node 20 + 22; the suite is verified timezone-independent (run under UTC, Asia/Kolkata, America/St_Johns).
  • Real-data validation against a live 780G is still pending (#12). Nothing in this release has been tested against a real CareLink account.

v0.1.2 — remove unused proxy code; supply-chain reduction

Choose a tag to compare

@NovaLux12 NovaLux12 released this 19 Jul 14:02

Removes the proxy code path that became dead code after the v0.1.1 USE_PROXY=false default. Pure hygiene + supply-chain reduction.

What's in this release

Supply-chain reduction

  • Removed https-proxy-agent and socks-proxy-agent from runtime dependencies. Both packages are pure attack surface for a medical-data bridge — neither is referenced anywhere in the production code path now that the default is safe.
  • Deleted src/carelink/proxy.ts (94 lines). The loadProxyList, createProxyAgent, and ProxyRotator helpers had no remaining callers after the v0.1.1 default change.
  • Removed USE_PROXY env var, the https.txt config file, and the corresponding .gitignore / .env.example entries.

Behavioural fix (incidental)

  • The previous fetch() had maxRetry = this.proxyRotator.hasProxies ? 10 : 1 — meaning default users got exactly 1 retry attempt, masked by the proxy-aware logic. New code: 3 attempts with exponential backoff (2s, 4s, 8s). This is a strict improvement for everyone; no regressions.

Migration for power users

If you were using https.txt + USE_PROXY=true to route CareLink traffic through a proxy:

# Before
echo "1.2.3.4:8080" > https.txt
USE_PROXY=true npm start

# After
HTTPS_PROXY=http://1.2.3.4:8080 npm start
# (or with auth: HTTPS_PROXY=http://user:pass@1.2.3.4:8080)

axios respects HTTPS_PROXY / HTTP_PROXY / ALL_PROXY / NO_PROXY natively. No bridge-specific config required.

Verification

  • npx tsc --noEmit: clean
  • npm test: 27/27 pass
  • npm audit --omit=dev: 0 vulnerabilities
  • Net diff: -146 / +18 lines

Credits

PR #4 by @NovaLux12.

Upstream relationship

No upstream PR — this is a deliberate security choice (removing attack surface). Documented in the PR's "Why" section. If upstream becomes active again, this divergence is a candidate for upstream discussion.

v0.1.1 — post-release hygiene + drop Node 18

Choose a tag to compare

@NovaLux12 NovaLux12 released this 19 Jul 13:53

Patch release covering post-v0.1.0 review follow-through and a Node 18 EOL decision.

Why v0.1.1?

A post-v0.1.0 review surfaced 2 critical and 5 high-priority issues. This release ships the fixes that don't change runtime behaviour but tighten security defaults, sync version metadata, and rebalance the supported Node versions.

What's in this release

Security hygiene

  • USE_PROXY default flipped from true to false. The previous default would silently route all CareLink traffic through the proxies listed in https.txt if that file existed — a footgun for a medical-data bridge. New users get no proxying; power users opt in explicitly with USE_PROXY=true. README documents the new default.
  • Removed undocumented dotenv.config({ path: 'my.env' }) lookups from src/main.ts and src/login.ts. These were upstream legacy, never documented, gitignored but confusing for anyone reading the entrypoint.
  • SECURITY.md contact clarified. Removed the NovaLux12@users.noreply.github.com email line (GitHub's auto-generated no-reply addresses do not accept inbound mail). Security Advisories are now the sole contact channel.

Metadata sync

  • package.json version is now 0.1.0 to match the v0.1.0 git tag. Was inherited from upstream at 2.0.0 — would have caused npm install carelink-bridge to report the wrong version.

Test coverage

  • Regression test for the cherry-picked BLE device detection fix (upstream PR #2 by @terminalcommand). Extracted isBleDevice from a private method to a module-level export; added 7 cases including the exact bug condition (deviceFamily: 'BLE_MINIMED', medicalDeviceFamily: undefined).
  • 27/27 tests pass (was 20/20 before v0.1.0).

Platform support

  • Node 18 dropped from CI matrix and engines.node. Node 18 was EOL'd upstream on 2025-04-30. Vitest 4 (the supported line, which fixes 5 transitive dev CVEs) does not support Node 18. Now targeting Node 20+.
  • vitest bumped to ^4.1.10. Kills 5 transitive dev CVEs (esbuild GHSA-67mh-4wv8-2f99, vite moderate/high, vitest critical, @vitest/mocker, vite-node). All dev-only — no runtime impact.

Repo hygiene

  • Issues enabled on the repo (was disabled by default for forks). The shipped .github/ISSUE_TEMPLATE/ files are now reachable.
  • Dependabot security updates enabled. Auto-PRs will fire for any future CVE.
  • Branch protection on main — CI required, linear history, no force pushes, no branch deletion, conversation resolution required, admins included.

Credits

All new code in this release is by @NovaLux12. The BLE detection fix is by @terminalcommand, co-authored by Nicolas Raverdy (@nraverdy).

Upstream relationship

No behavioural divergence from upstream in this release. Every change is either (a) a hygiene fix for inherited upstream quirks (USE_PROXY default, my.env lookup, package.json version), (b) additive (tests, docs, repo config), or (c) a CVE fix on the supported dev toolchain. The fork continues to carry only changes that landed in or were submitted upstream — the BLE fix remains cherry-picked from upstream PR #2.

v0.1.0 — community fork

Choose a tag to compare

@NovaLux12 NovaLux12 released this 18 Jul 22:39

First tagged release of the community fork.

This is a fork of domien-f/carelink-bridge maintained while upstream is quiet. Original code by @domien-f.

What's in this release

  • All upstream code (3 commits from domien-f).
  • @terminalcommand's upstream PR #2 — fixes BLE device detection for patient accounts. Resolves empty-data / no-SGV-upload issue on 780G, Guardian 4, and Simplera CGM devices. Co-authored by Nicolas Raverdy (@nraverdy). Cherry-picked with full author preservation.
  • CIvitest + tsc --noEmit on Node 18, 20, 22.
  • Community repo hygiene — issue templates, PR template, Dependabot, CODEOWNERS, labels.