{"_id":"@alimirzayev/react-native-background-timer","name":"@alimirzayev/react-native-background-timer","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@alimirzayev/react-native-background-timer","version":"0.1.0","description":"Reliable lifecycle-aware timers for modern React Native and Expo development builds","main":"./lib/module/index.js","types":"./lib/typescript/index.d.ts","exports":{".":{"react-native":"./src/index.ts","types":"./lib/typescript/index.d.ts","default":"./lib/module/index.js"},"./package.json":"./package.json"},"scripts":{"clean":"del-cli lib coverage","prepare":"bob build","prepublishOnly":"npm run verify","typecheck":"tsc --noEmit","lint":"eslint src tests","test":"jest --runInBand --coverage","verify":"npm run typecheck && npm run lint && npm test && npm run prepare && npm pack --dry-run","verify:examples":"npm run typecheck --workspaces --if-present && npm run export:web --workspace background-timer-expo-example && npm run bundle:android --workspace background-timer-bare-example && npm run bundle:ios --workspace background-timer-bare-example","example:expo":"npm run start --workspace background-timer-expo-example","example:expo:web":"npm run web --workspace background-timer-expo-example","example:bare":"npm run start --workspace background-timer-bare-example"},"workspaces":["examples/*"],"keywords":["react-native","expo","background","timer","turbomodule"],"repository":{"type":"git","url":"git+https://github.com/alimirzayev/react-native-background-timer.git"},"bugs":{"url":"https://github.com/alimirzayev/react-native-background-timer/issues"},"homepage":"https://github.com/alimirzayev/react-native-background-timer#readme","author":{"name":"Ali Mirzayev"},"license":"MIT","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/","provenance":true},"engines":{"node":"^20.19.4 || ^22.13.0 || >=24.3.0"},"peerDependencies":{"react":">=19.1.0","react-native":">=0.82.0"},"devDependencies":{"@eslint/js":"^10.0.1","@react-native/babel-preset":"0.86.0","@react-native/jest-preset":"0.86.0","@react-native/typescript-config":"0.86.0","@types/jest":"^29.5.14","@types/node":"^24.0.0","@types/react":"^19.2.0","del-cli":"^7.0.0","eslint":"^10.7.0","jest":"^29.7.0","prettier":"^3.9.5","react":"19.2.3","react-native":"0.86.0","react-native-builder-bob":"^0.43.0","typescript":"6.0.3","typescript-eslint":"^8.63.0"},"react-native-builder-bob":{"source":"src","output":"lib","targets":[["module",{"esm":true}],["typescript",{"project":"tsconfig.build.json"}]]},"codegenConfig":{"name":"AlimirzayevBackgroundTimerSpec","type":"modules","jsSrcsDir":"src","android":{"javaPackageName":"com.alimirzayev.backgroundtimer"}},"_id":"@alimirzayev/react-native-background-timer@0.1.0","gitHead":"04b570425e709e19b1c1faf03b9dd7301c2c1c95","_nodeVersion":"24.14.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-+1wzctaPhVhHDdL4e+qnwJyrUn980SLwKX9EpHrb8NTuxiCk82NuJvDA8p+ztu5CVSLyGC2W+2VclgA/kDYNjQ==","shasum":"116b44244be5215a924e3b1ef5656cd0f761f9be","tarball":"https://registry.npmjs.org/@alimirzayev/react-native-background-timer/-/react-native-background-timer-0.1.0.tgz","fileCount":59,"unpackedSize":83375,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDAok+srvsyh7UZU3KQsqWpCPdZ8T+vmETbg7XneBD6XAiEA4sFTzEVzH3kVbDt+PHhCA8VzvSrRW0uamQUy083PBq8="}]},"_npmUser":{"name":"alimirzayev","email":"alimirzayev0414@gmail.com"},"directories":{},"maintainers":[{"name":"alimirzayev","email":"alimirzayev0414@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native-background-timer_0.1.0_1783959389344_0.0176815472143792"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-13T16:16:29.219Z","0.1.0":"2026-07-13T16:16:29.499Z","modified":"2026-07-13T16:16:29.748Z"},"maintainers":[{"name":"alimirzayev","email":"alimirzayev0414@gmail.com"}],"description":"Reliable lifecycle-aware timers for modern React Native and Expo development builds","homepage":"https://github.com/alimirzayev/react-native-background-timer#readme","keywords":["react-native","expo","background","timer","turbomodule"],"repository":{"type":"git","url":"git+https://github.com/alimirzayev/react-native-background-timer.git"},"author":{"name":"Ali Mirzayev"},"bugs":{"url":"https://github.com/alimirzayev/react-native-background-timer/issues"},"license":"MIT","readme":"<div align=\"center\">\n\n# @alimirzayev/react-native-background-timer\n\n### Modern background-aware timers for the React Native New Architecture\n\nBuilt from scratch with **TurboModules + Codegen**, first-class **TypeScript**, real native cancellation, Expo development builds, and a safe web fallback.\n\n[![CI ready](https://img.shields.io/badge/CI-ready-2088FF?logo=githubactions&logoColor=white)](./.github/workflows/ci.yml)\n[![npm ready](https://img.shields.io/badge/npm-publish%20ready-CB3837?logo=npm&logoColor=white)](./package.json)\n[![React Native](https://img.shields.io/badge/React%20Native-0.82--0.86%20verified-61dafb?logo=react)](https://reactnative.dev/)\n[![Expo](https://img.shields.io/badge/Expo-development%20builds-000020?logo=expo)](https://docs.expo.dev/develop/development-builds/introduction/)\n[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)\n\n[Getting started](#getting-started) · [Why this package?](#why-this-package) · [API](#api) · [Platform behavior](#platform-behavior) · [Migration](#migration-from-react-native-background-timer)\n\n</div>\n\n> [!IMPORTANT]\n> This is a modern, clean implementation - not a fork of the original package. It is designed for current React Native projects and explicitly documents what mobile operating systems can and cannot guarantee.\n\n## At a glance\n\n- **New Architecture first** - typed TurboModule spec, Codegen events, Hermes-ready.\n- **Expo-ready** - works in Expo development builds through standard autolinking; no config plugin required.\n- **Correct cancellation** - clearing a timer removes both its JavaScript callback and native scheduled work.\n- **Multiple timers** - independent timeouts and intervals with one shared native event subscription.\n- **Stable cadence** - monotonic Android deadlines skip missed ticks instead of creating callback storms.\n- **Lifecycle-safe** - native timers, listeners, background assertions, and WakeLocks are cleaned up.\n- **TypeScript included** - no separate `@types` package.\n- **Web-safe** - the same API works through a foreground-only JavaScript fallback.\n- **Tested release path** - CI, coverage thresholds, native lint/tests, and a publish-blocking verification step.\n\n## Why this package?\n\nThe original `react-native-background-timer` was created for the legacy React Native bridge. This package preserves the familiar timer experience while rebuilding the native and JavaScript layers around the current React Native architecture.\n\n| Area                | Legacy approach                          | This package                                 |\n| ------------------- | ---------------------------------------- | -------------------------------------------- |\n| Native architecture | Legacy bridge module                     | TurboModule + Codegen                        |\n| Events              | Manual `NativeEventEmitter` wiring       | Typed Codegen events                         |\n| TypeScript          | External/community definitions           | Built in                                     |\n| Cancellation        | Reported timeout/interval cleanup issues | JS and native work cancelled together        |\n| Concurrent timers   | Historically inconsistent APIs           | Independent timers by design                 |\n| Long-running IDs    | Callback object growth / range reports   | `Map` storage and safe ID recycling          |\n| Timing cadence      | Repeating delay accumulation             | Monotonic deadlines and missed-tick skipping |\n| Expo                | Legacy eject-oriented setup              | Expo development builds + autolinking        |\n| Web                 | No dependable package fallback           | Foreground-compatible web driver             |\n| Verification        | No current regression suite              | Jest, Android unit/lint, host builds, CI     |\n\n### Issue classes addressed\n\nThe implementation includes targeted regressions for common reports from the original library:\n\n- **New Architecture and builds:** `#536`, `#532`, `#530`, `#527`, `#526`, `#367`, `#290`, `#242`\n- **Immediate, long-running, and synchronized timers:** `#533`, `#529`, `#270`, `#271`, `#256`, `#299`\n- **Cancellation and multiple timers:** `#524`, `#337`, `#310`, `#366`\n- **Safe missing-native-module behavior:** `#531`\n- **React Native Web fallback:** `#455`\n- **iOS reload cleanup protections:** `#460` (device stress loop remains pending)\n\nSee the [issue regression matrix](./ISSUES.md) for test details. OS-controlled behavior such as iOS suspension, Android Doze, OEM process killing, or force-quit is documented as a limitation - not presented as a library fix.\n\n## Compatibility\n\n| Target       | Support                                                         |\n| ------------ | --------------------------------------------------------------- |\n| React Native | Verified on `0.82.1`, `0.83.10`, `0.84.1`, `0.85.3`, and `0.86` |\n| React        | `>=19.1`                                                        |\n| Architecture | New Architecture / TurboModules                                 |\n| Expo         | SDK 57 development builds verified; Expo Go is not supported    |\n| Android      | API 24+, compile SDK 36                                         |\n| iOS          | 16.4+                                                           |\n| Web          | Expo Web / React Native Web foreground fallback                 |\n\n> [!NOTE]\n> React Native 0.82.1 passes Android normally. With Xcode 26.5, its bundled `fmt 11.0.2` pod must be compiled as C++17 due to an upstream toolchain incompatibility. This does not originate in this package and is not required for React Native 0.83+.\n\n## Getting started\n\n### Install\n\n```sh\nnpm install @alimirzayev/react-native-background-timer\n```\n\n```sh\nyarn add @alimirzayev/react-native-background-timer\n```\n\n### Bare React Native\n\nAndroid uses standard autolinking. For iOS, install pods after adding the package:\n\n```sh\ncd ios && pod install\n```\n\nRebuild the native application after installation.\n\n### Expo\n\nThis package contains native code, so use an Expo development build:\n\n```sh\nnpx expo install @alimirzayev/react-native-background-timer\nnpx expo run:android\n# or\nnpx expo run:ios\n```\n\n> [!WARNING]\n> **Expo Go is not supported.** Package import is safe, but starting a native timer without a development build throws an actionable error.\n\n## Quick start\n\n```ts\nimport BackgroundTimer from \"@alimirzayev/react-native-background-timer\";\n\nconst timerId = BackgroundTimer.setInterval(\n  () => {\n    console.log(\"tick\");\n  },\n  1_000,\n  { immediate: true },\n);\n\n// Later: removes the callback and native timer.\nBackgroundTimer.clearInterval(timerId);\n```\n\n### Timeout\n\n```ts\nconst timeoutId = BackgroundTimer.setTimeout(() => {\n  console.log(\"finished\");\n}, 2_000);\n\nBackgroundTimer.clearTimeout(timeoutId);\n```\n\n### Handle iOS background-time expiration\n\n```ts\nconst unsubscribe = BackgroundTimer.addBackgroundTimeExpiredListener(() => {\n  // Save state and stop background work gracefully.\n  console.log(\"iOS background time expired\");\n});\n\nunsubscribe();\n```\n\n### Inspect platform capabilities\n\n```ts\nconst capabilities = BackgroundTimer.getCapabilities();\n\nconsole.log(capabilities.backgroundExecution);\n// Android: \"best-effort\"\n// iOS:     \"time-limited\"\n// Web:     \"none\"\n```\n\n## API\n\n| Method                                          | Returns             | Description                             |\n| ----------------------------------------------- | ------------------- | --------------------------------------- |\n| `setTimeout(callback, delay?)`                  | `TimerId`           | Schedule one callback                   |\n| `clearTimeout(id)`                              | `void`              | Cancel one timeout                      |\n| `setInterval(callback, delay?, options?)`       | `TimerId`           | Schedule a repeating callback           |\n| `clearInterval(id)`                             | `void`              | Cancel one interval                     |\n| `clearAllTimers()`                              | `void`              | Cancel all timers owned by this package |\n| `addBackgroundTimeExpiredListener(listener)`    | `unsubscribe`       | Observe iOS expiration                  |\n| `getCapabilities()`                             | `TimerCapabilities` | Inspect runtime guarantees              |\n| `runBackgroundTimer(callback, delay, options?)` | `TimerId`           | Single-timer migration helper           |\n| `stopBackgroundTimer()`                         | `void`              | Stop the migration-helper timer         |\n\n`options.immediate` fires an interval once immediately, then continues at the requested delay. Delays must be finite values from `0` through `2,147,483,647` milliseconds; repeating intervals use a minimum of `1` millisecond.\n\nThe full API contract is documented in [API.md](./API.md).\n\n## Platform behavior\n\n### Android\n\n- Schedules native timers from monotonic deadlines.\n- Supports independent one-shot and repeating timers.\n- Holds a partial WakeLock only while the host is backgrounded and active timers remain.\n- Releases callbacks and WakeLock state on clear, resume, host destruction, or module invalidation.\n- Skips missed ticks instead of replaying a callback storm.\n\nAndroid execution is **best effort**. Doze, force-stop, OEM battery policies, or process pressure can stop the app. Continuous user-visible work belongs in a foreground service with a visible notification.\n\n### iOS\n\n- Uses one GCD timer source per timer.\n- Requests a UIKit background task when active timers enter the background.\n- Coalesces missed repeating ticks.\n- Emits an expiration event when iOS revokes background time.\n- Ends timers and background assertions during clear, foregrounding, invalidation, and deallocation.\n\niOS background execution is **time limited**. After the granted time expires, iOS may suspend the app. No timer library can promise indefinite execution or execution after force-quit.\n\n### Web\n\n- Automatically selects a JavaScript driver.\n- Provides the same timeout, interval, cancellation, and capability APIs.\n- Never claims native background execution.\n\nBrowsers can throttle or suspend timers in inactive tabs. Web support is API compatibility for foreground use.\n\n## Choose the right background tool\n\nUse this package when you need second- or millisecond-level callbacks while the application process still has permission to execute.\n\n| Requirement                                  | Recommended tool                                    |\n| -------------------------------------------- | --------------------------------------------------- |\n| Short, frequent callbacks while backgrounded | This package                                        |\n| Deferrable sync or maintenance work          | Expo BackgroundTask / WorkManager / BGTaskScheduler |\n| Alarm or user-visible event at a future time | Local notifications                                 |\n| Continuous Android work                      | Foreground service                                  |\n| Work after force-quit                        | OS-specific scheduling; not a timer                 |\n\nFor countdowns and stopwatches, store a timestamp and calculate elapsed time when the app resumes instead of depending on every tick.\n\n## Migration from `react-native-background-timer`\n\nChange the import:\n\n```diff\n- import BackgroundTimer from 'react-native-background-timer';\n+ import BackgroundTimer from '@alimirzayev/react-native-background-timer';\n```\n\nStandard calls keep the familiar shape:\n\n```ts\nconst id = BackgroundTimer.setInterval(callback, 1_000);\nBackgroundTimer.clearInterval(id);\n```\n\nFor older code using a single global background timer:\n\n```ts\nBackgroundTimer.runBackgroundTimer(callback, 1_000);\nBackgroundTimer.stopBackgroundTimer();\n```\n\nThe migration helpers intentionally own only one timer. Prefer the core timeout and interval API for new code.\n\n## Verification\n\n- **38 Jest tests** across timer engine, native driver, web driver, and issue regressions.\n- **98.46% statements**, **95.31% branches**, **100% functions**, **99.13% lines**.\n- Android native unit tests and lint pass.\n- Bare React Native Android APK and iOS simulator application builds pass.\n- Expo SDK 57 Android, iOS, and web host builds pass.\n- Packaged `.tgz` clean-install, autolinking, types, and Metro bundles pass.\n- CI enforces coverage and package verification.\n- `prepublishOnly` blocks npm publication when verification fails.\n\nRunnable examples:\n\n- [Expo development build example](https://github.com/alimirzayev/react-native-background-timer/tree/main/examples/expo)\n- [Bare React Native example](https://github.com/alimirzayev/react-native-background-timer/tree/main/examples/bare)\n\n## Development\n\n```sh\nnpm install\nnpm run verify\n```\n\nNative Android verification:\n\n```sh\ncd examples/bare/android\n./gradlew \\\n  :alimirzayev_react-native-background-timer:testDebugUnitTest \\\n  :alimirzayev_react-native-background-timer:lintDebug\n```\n\n## License\n\nMIT © Ali Mirzayev\n","readmeFilename":"README.md","_rev":"1-01e56716fda093f8ffa7ae06859a4d46"}