Thanks for considering a contribution. NativeProbe is a small, focused project — please read this before opening a PR so your change fits its scope and conventions.
bun install
bun startMost probes only make sense on a physical device (sensors, location, haptics, biometrics, deep links) — a simulator/emulator is fine for reviewing UI, but verify device-touching changes on real hardware before opening a PR.
bun run lint # eslint + prettier -c
bun run typecheck # tsc --noEmit
bun run test # jest + jest-expo + react native testing libraryAll three must pass. CI runs the same checks.
- TypeScript strict mode, no unnecessary
any. - ESLint (
eslint-config-expo) lints, Prettier formats — don't hand-format, runbun run format. - No premature abstraction: a pattern gets extracted once two probes actually share it, not before.
- User-visible strings live in
src/i18n/locales/*.json, never hardcoded in a component. - Keep native subscriptions (sensors, location, network listeners) cleaned up in a
useEffectreturn — this is the kind of bug that's easy to miss and annoying to debug.
Conventional Commits, English, lowercase:
feat: add barometer probe
fix: clean up accelerometer listener on unmount
docs: clarify location permission flow
A probe is three pieces wired together:
- Metadata — add an entry to
probesinsrc/probes/registry.ts:id,category,titleKey/descriptionKey(i18n keys),platforms, anicon(any Ionicons name), and agetAvailability()function returning aProbeAvailability("available" | "permission-required" | "denied" | "restricted" | "unsupported" | "unknown"). A normal top-level import of the Expo module it needs is fine — Jest (viajest-expo) parses React Native's source without issue. - Translations — add
probe.<id>.title/probe.<id>.description(and any field labels the screen needs) to bothsrc/i18n/locales/en.jsonandsrc/i18n/locales/fr.json. English is the fallback, so it must always be complete; keep French in sync in the same PR. - Screen — create
src/features/<id>/<id>-screen.tsxfollowing the pattern insrc/features/battery/battery-screen.tsx(a simple probe) orsrc/features/sensors/(a probe family sharing one screen/hook). Wrap it inProbeScreenShellfor the standard title/status/description/"Built with" chrome, then register the component insrc/probes/screens.tsx'sprobeScreensmap.
That's it — the Overview screen, routing, and status counting all pick up the new probe automatically from the registry.
Add a <id>-screen.test.tsx alongside the screen using
renderWithProviders from src/test-utils/render.tsx — see
src/features/haptics/haptics-screen.test.tsx for a screen with button
interactions, or src/features/overview/overview-screen.test.tsx for a
plain render assertion. Mock the native module's specific function with
jest.spyOn rather than mocking the whole package.
See SECURITY.md — please don't open a public issue for a vulnerability.