Skip to content

feat: @kingstinct/exact-healthkit, HealthKit for Exact apps - #402

Draft
robertherber wants to merge 4 commits into
masterfrom
feat/exact-healthkit
Draft

robertherber wants to merge 4 commits into
masterfrom
feat/exact-healthkit

Conversation

@robertherber

@robertherber robertherber commented Nov 14, 2026 •

Copy link
Copy Markdown
Member

What

A new package, packages/exact-healthkit (@kingstinct/exact-healthkit). It exposes react-native-healthkit's functionality as an Exact package: an interface (exact.json, 53 names, 56 shapes) and a Swift implementation for iOS (apple/).

  • Same names: the library's functions keep their names and take keyword options. Reads are Exact sources; saves, deletes and authorization are sends.
  • Live reads: an HKObserverQuery per sample type re-asks the type's readers when it changes. This replaces subscribeToChanges and the hooks.
  • Permissions: each type is its own permission (healthkit.read.<id>, healthkit.share.<id>). requestAuthorization asks for all of them in one sheet. A read of a type never asked for fails with NotAllowedError. A denied read answers only the app's own samples, as HealthKit does.
  • No config plugin: Exact derives the entitlement and usage strings from the app's grants.
  • Agent mode: under Exact's agent it answers from an in-memory store seeded with fixture/health.json (compiled in) and keeps what the app saves and deletes.
  • Generated files: scripts/manifest.mjs generates exact.json. scripts/tables.mjs generates apple/Tables.swift from react-native-healthkit's HealthKit schema. bun run check fails when either is stale.

The README has the full mapping from the RN API: dates in ms, metadata as entries, anyOf/allOf/noneOf filters, workout proxy methods taking workoutUuid.

Example app

apps/exact-example is an Exact app using the package, the counterpart of apps/example. It has three tabs:

  • Today: steps, active energy, distance, latest heart rate and the week's steps.
  • Workouts: a list that opens a detail screen.
  • Log: saves a weight to Health and lists the recent ones.
Before access Today Workouts A workout Log

iPhone 18 Pro simulator, under Exact's agent over the package's fixture. Log is shown after saving 71.9 kg, which tops the recent list.

It sits outside the Bun workspace (root workspaces is now apps/example and packages/*) and installs the package with file:, because Exact builds a package only from the app's own node_modules. It expects an exact checkout next to the repo, or EXACT set.

Not included

  • Background delivery: Exact's iOS host only wakes apps for regions and transfers, so this needs a host change in Exact.
  • No Objective-C exception catcher: Exact packages are Swift-only, so unit strings and writes to read-only types are validated in Swift before HealthKit sees them.

Repo changes outside the package

  • biome.json ignores the generated exact.json.
  • tsconfig.json excludes test/fixture, whose types only exist inside an Exact app.
  • bun.lock gains the new workspace.
  • A changeset adds the package at 0.x, outside the lockstep-versioned group.

Test plan

  • Exact's Contract compiler accepts the interface, the test app and the README's Contract example.
  • The test app builds for the iOS simulator (Xcode 27.2, Exact dcf4dd8b).
  • EXACT_DIR=… bun test/drive.mjs on an iPhone 18 Pro simulator under the agent: 9/9. Covers the read before asking, permission, fixture reads (samples, statistics, a filtered read, a daily max collection), a save read back, and deny.
  • Example: bun exact.mjs test ios (1/1, before access) and bun test/drive.mjs (7/7: Today, Workouts and its detail, a weight saved and read back) on the simulator under the agent
  • bun lint, bun typecheck, bun run check
  • The HealthKit-backed path on the simulator (agent ios --bind exact-healthkit, with Health access pre-granted by applesimutils). Reads, requestAuthorization and saveQuantitySample all go through real HealthKit. The observer query refreshed the reads after the save, and a filter became the expected NSPredicate. This run found and fixed one bug: saves answered the unsaved object, whose source revision was empty.
  • HealthKit's own permission sheet, on a simulator without the pre-grant
  • On a device

🤖 Generated with Claude Code

New package @kingstinct/exact-healthkit: react-native-healthkit's
functionality as an Exact (github.com/expo/exact) package, an interface
(exact.json) with a Swift implementation for iOS. Reads are live through
HealthKit observer queries; under Exact's agent it answers from an
in-memory fixture store. Background delivery is not supported yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5373331

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@kingstinct/exact-healthkit Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@react-native-healthkit/core@402
npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@kingstinct/exact-healthkit@402
npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@react-native-healthkit/health-records@402
npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@kingstinct/react-native-healthkit@402

commit: 5373331

robertherber and others added 3 commits November 14, 2026 11:22
HealthKit fills in a sample's source revision when it stores it, so
the object the package made answered an empty source. A save now reads
the stored copy back by uuid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An Exact app using @kingstinct/exact-healthkit, the Exact counterpart of
apps/example: Today (activity and the week's steps), Workouts (list and
detail) and Log (save a weight). app.test.contract covers the screen
before access; test/drive.mjs drives the flows after it under the agent.

The example installs the package with file: outside the Bun workspace,
since Exact builds packages only from the app's own node_modules. The
package's fixture gains a week of steps, energy, distance and weights.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant