npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@better-native/keep-awake

v0.0.1-alpha.1

Published

Effect-native screen wake-lock management for Expo applications.

Readme

@better-native/keep-awake

Effect-native screen wake-lock management with an Expo-compatible entrypoint.

The package has two public boundaries:

  • @better-native/keep-awake provides typed Effects, a scoped resource, a Stream, and an Effect Atom;
  • @better-native/keep-awake/expo preserves the expo-keep-awake import surface for incremental migration.

See Expo's KeepAwake documentation for the underlying native module and platform support. This guide documents the Better Native integration; API mapping coverage alone is not evidence of native behavioral parity.

Installation

Install the native provider, this package, and its Effect peer in one Expo CLI transaction:

npx expo install expo-keep-awake @better-native/keep-awake@alpha [email protected]

Expo selects the expo-keep-awake version compatible with the application's SDK. The Better Native and Effect specifications remain explicit because Expo does not version those third-party packages.

expo-keep-awake remains installed because Better Native delegates to its native module. After changing native dependencies, rebuild the development client or native application when the provider is not already present in that binary; restarting Metro alone does not update native binaries. The module does not require an application permission or package-specific config plugin.

Scoped Effect API

Prefer keepAwake for application work. It acquires a tagged lease and registers deactivation as an Effect finalizer, so normal completion, failure, and interruption all run cleanup.

import { keepAwake, live } from "@better-native/keep-awake"
import * as Effect from "effect/Effect"

const playVideo = Effect.scoped(
  Effect.gen(function* () {
    const tag = yield* keepAwake({ tag: "video-player" })
    yield* Effect.log(`Keeping the screen awake with ${tag}`)
    yield* Effect.never
  }),
).pipe(Effect.provide(live))

// Execute `playVideo` from an application boundary and interrupt its Fiber when playback ends.

Omit tag to receive a unique generated tag. Generated tags isolate concurrent scoped callers so one scope cannot deactivate another scope's lease. Supply a stable tag when application code needs to identify or share the same lease deliberately. Scoped leases with the same explicit tag are reference-counted per service: the first scope activates the native lease and only the last scope to close deactivates it.

keepAwake can fail with KeepAwakeUnavailable before acquisition or KeepAwakeFailure when the underlying operation fails. A deactivation failure occurs in the finalizer and is retained as an Effect defect rather than silently discarded.

Manual activation

The exact-name manual APIs are available for integrations that cannot use an Effect scope:

import {
  activateKeepAwakeAsync,
  deactivateKeepAwake,
  ExpoKeepAwakeTag,
  live,
} from "@better-native/keep-awake"
import * as Effect from "effect/Effect"

const activate = activateKeepAwakeAsync(ExpoKeepAwakeTag).pipe(Effect.provide(live))
const deactivate = deactivateKeepAwake(ExpoKeepAwakeTag).pipe(Effect.provide(live))

The tag is optional for the manual APIs. Omitting it uses ExpoKeepAwakeTag, matching Expo's shared default. Activating two independent features with that default means either feature can deactivate the shared lease, so prefer explicit tags or the scoped keepAwake API for concurrent work.

activateKeepAwake is retained only as Expo's deprecated exact-name alias. New code should use activateKeepAwakeAsync.

Events and React

addListener(tag?) is the Effect-native Stream counterpart of Expo's listener API. Its subscription is removed when the consuming Stream scope closes. Expo documents keep-awake state events as a web facility; do not use event delivery as a native lifecycle signal.

keepAwakeAtom(tag?) is the React integration. Mount it through @effect/atom-react to acquire a lease and unmount its last consumer to release it. Calls using the same explicit tag return the same Atom and share one lease. Calls without a tag share the package's untagged Atom, whose underlying scoped acquisition still receives an isolated generated lease tag.

Expo-compatible import

For a low-churn migration, change only the module specifier:

import { useKeepAwake } from "@better-native/keep-awake/expo"

The /expo entrypoint is generated from the pinned Expo surface and delegates to expo-keep-awake. Its hooks and Promise-based functions retain Expo behavior and types; they do not return Effects. Import from the package root when opting into the Effect-native API.

The repository compatibility harness can also route the unchanged expo-keep-awake specifier to this generated entrypoint in a candidate bundle. That Metro routing is test infrastructure, not a requirement for applications that import @better-native/keep-awake/expo directly.

Evidence boundaries

Use bun run coverage from the repository root to inspect exact export mappings. Use the paired compatibility harness for platform behavior evidence. Unit tests, a successful build, the quick interactive smoke suite, and deterministic DX evals validate narrower contracts; none alone proves platform parity.

The current prototype has paired Release evidence for the pinned Expo revision on an iOS 26.5 simulator, an Android API 36 emulator, and Playwright Chromium. The pinned native KeepAwake source matched all four cases on iOS and Android. Web uses the reviewed supplemental KeepAwake capability source and matched all seven cases across default and explicit tags, hook lifecycle, listener cleanup, release events, platform errors, and concurrent-tag isolation. Expo's pinned web source is not used as the web verdict because its afterAll deactivates already-released tags and fails against Expo's own web implementation. These results are simulator, emulator, and browser evidence—not physical-device evidence. No paid-evaluation result is claimed by this package guide.

On that evidence, compatibility/ownership.json classifies the root expo-keep-awake contract as effect owned. The ownership claim covers Better Native's JavaScript API, lifecycle behavior, and candidate replacement; the live layer still uses Expo as its native capability provider.