@symbiote-native/keep-awake 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/build/angular/index.d.ts +2 -0
  4. package/build/angular/index.js +4 -0
  5. package/build/angular/services/keep-awake.service/index.d.ts +5 -0
  6. package/build/angular/services/keep-awake.service/index.js +83 -0
  7. package/build/core/index.d.ts +3 -0
  8. package/build/core/index.js +1 -0
  9. package/build/core/keep-awake.d.ts +17 -0
  10. package/build/core/keep-awake.js +41 -0
  11. package/build/core/native-module.d.ts +9 -0
  12. package/build/core/native-module.js +3 -0
  13. package/build/core/types.d.ts +8 -0
  14. package/build/core/types.js +1 -0
  15. package/build/react/hooks/use-keep-awake/index.d.ts +2 -0
  16. package/build/react/hooks/use-keep-awake/index.js +35 -0
  17. package/build/react/index.d.ts +2 -0
  18. package/build/react/index.js +5 -0
  19. package/build/vue/composables/use-keep-awake/index.d.ts +2 -0
  20. package/build/vue/composables/use-keep-awake/index.js +28 -0
  21. package/build/vue/index.d.ts +2 -0
  22. package/build/vue/index.js +5 -0
  23. package/build-ngc/angular/index.d.ts +2 -0
  24. package/build-ngc/angular/index.js +5 -0
  25. package/build-ngc/angular/index.js.map +1 -0
  26. package/build-ngc/angular/services/keep-awake.service/index.d.ts +8 -0
  27. package/build-ngc/angular/services/keep-awake.service/index.js +41 -0
  28. package/build-ngc/angular/services/keep-awake.service/index.js.map +1 -0
  29. package/build-ngc/core/index.d.ts +3 -0
  30. package/build-ngc/core/index.js +2 -0
  31. package/build-ngc/core/index.js.map +1 -0
  32. package/build-ngc/core/keep-awake.d.ts +17 -0
  33. package/build-ngc/core/keep-awake.js +42 -0
  34. package/build-ngc/core/keep-awake.js.map +1 -0
  35. package/build-ngc/core/native-module.d.ts +9 -0
  36. package/build-ngc/core/native-module.js +4 -0
  37. package/build-ngc/core/native-module.js.map +1 -0
  38. package/build-ngc/core/types.d.ts +8 -0
  39. package/build-ngc/core/types.js +2 -0
  40. package/build-ngc/core/types.js.map +1 -0
  41. package/native-link.json +12 -0
  42. package/package.json +107 -0
  43. package/src/angular/index.ts +14 -0
  44. package/src/angular/services/keep-awake.service/index.ts +46 -0
  45. package/src/angular/services/keep-awake.service/keep-awake.service.test.ts +98 -0
  46. package/src/core/index.ts +9 -0
  47. package/src/core/keep-awake.test.ts +119 -0
  48. package/src/core/keep-awake.ts +50 -0
  49. package/src/core/native-module.ts +20 -0
  50. package/src/core/types.ts +14 -0
  51. package/src/react/hooks/use-keep-awake/index.ts +43 -0
  52. package/src/react/hooks/use-keep-awake/use-keep-awake.test.tsx +70 -0
  53. package/src/react/index.ts +16 -0
  54. package/src/vue/composables/use-keep-awake/index.ts +36 -0
  55. package/src/vue/composables/use-keep-awake/use-keep-awake.test.ts +76 -0
  56. package/src/vue/index.ts +16 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 A. Prokopenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # @symbiote-native/keep-awake
2
+
3
+ Port of [`expo-keep-awake`](https://docs.expo.dev/versions/latest/sdk/keep-awake/) for
4
+ [SymbioteNative](../../README.md) — keeps the screen on for the lifetime of a mounted
5
+ component/composable/service, reachable from every adapter (React, Vue, Angular), not just
6
+ React.
7
+
8
+ Built the same way as [`@symbiote-native/battery`](../battery) and
9
+ [`@symbiote-native/device`](../device), an `expo-modules-core`-based wrapper (see the
10
+ `symbiote-expo-native-module` project skill for the full mechanism: why `expo-modules-core` is
11
+ depended on directly and never the `expo` meta-package, why the upstream JS is hand-ported into
12
+ `core/` rather than imported, and how autolinking picks up the native module).
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @symbiote-native/keep-awake
18
+ ```
19
+
20
+ Depends on `expo-keep-awake` and `expo-modules-core` directly (regular dependencies, pinned to
21
+ exact versions — never a caret range, since this package's `core/` is hand-ported against one
22
+ specific native API shape and a newer resolve could silently drift the two apart). Never install
23
+ `expo-keep-awake` yourself, and never add the `expo` package to this project — it bundles its own
24
+ Metro/Babel pipeline that conflicts with this project's own.
25
+
26
+ ### Required one-time step: native autolinking wiring
27
+
28
+ Unlike a plain RN native module, `expo-keep-awake`'s native code is discovered by
29
+ `expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
30
+ into the native host app **once**, covering this package and every other `expo-modules-core`
31
+ package (`@symbiote-native/battery`, `@symbiote-native/device`, `@symbiote-native/sensors`, …)
32
+ with zero further changes:
33
+
34
+ | Platform | Touches |
35
+ |---|---|
36
+ | iOS | `ios/Podfile` — add `use_expo_modules!` |
37
+ | iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
38
+ | Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
39
+ | Android | `MainApplication.kt` — Expo's bootstrap hook, plus a hand-written native-module name map (there's no `expo` meta-package here to auto-generate one) |
40
+
41
+ The recurring per-package half of the Android wiring (`app/build.gradle`'s
42
+ `implementation project(':expo-keep-awake')` line and `MainApplication.kt`'s module-name map
43
+ entry) is automated by this package's own `postinstall` script via
44
+ `@symbiote-native/expo-modules-link` — see that package's README for how the `native-link.json`
45
+ manifest above drives it. Full mechanics — the Podfile pieces that normally ship inside the
46
+ `expo` package, the `expo` peer-dependency exclusion list — live in the
47
+ `symbiote-expo-native-module` skill.
48
+
49
+ No platform permission string is needed — keeping the screen awake has no runtime permission
50
+ prompt on either platform.
51
+
52
+ ## Shape
53
+
54
+ ```
55
+ src/core/ keep-awake.ts — isAvailableAsync/activateKeepAwakeAsync/
56
+ deactivateKeepAwake/addListener, ExpoKeepAwakeTag. native-module.ts
57
+ resolves the native module through expo-modules-core's
58
+ requireNativeModule. types.ts — KeepAwakeEvent/KeepAwakeListener/
59
+ KeepAwakeOptions, hand-ported from KeepAwake.types.ts.
60
+ src/react/hooks/ @symbiote-native/keep-awake/react — useKeepAwake
61
+ src/vue/composables/ @symbiote-native/keep-awake/vue — useKeepAwake
62
+ src/angular/services/ @symbiote-native/keep-awake/angular — KeepAwakeService (`.connect()`,
63
+ no return value — a pure side effect for the component's lifetime)
64
+ ```
65
+
66
+ Each adapter's hook/composable/service activates a keep-awake lock on mount and deactivates it on
67
+ unmount, over the same `core` functions — the tag-generation and activate/deactivate lifecycle is
68
+ written once and shared by all three. React uses `useId()` for its default per-instance tag,
69
+ matching upstream; Vue and Angular have no `useId` equivalent, so both fall back to a small
70
+ monotonically-incrementing module-local counter (`keep-awake-tag-1`, `keep-awake-tag-2`, …) when
71
+ no explicit tag is given.
72
+
73
+ ## Use it
74
+
75
+ ```tsx
76
+ // React — examples/expo-react/screens/KeepAwakeScreen.tsx
77
+ import { useKeepAwake } from '@symbiote-native/keep-awake/react';
78
+
79
+ function KeepAwakeScreen() {
80
+ useKeepAwake(); // screen stays on for as long as this component is mounted
81
+
82
+ return <Text>Screen will not sleep</Text>;
83
+ }
84
+ ```
85
+
86
+ ```vue
87
+ <!-- Vue — examples/expo-vue-sfc/screens/KeepAwakeScreen.vue -->
88
+ <script setup lang="ts">
89
+ import { useKeepAwake } from '@symbiote-native/keep-awake/vue';
90
+
91
+ useKeepAwake();
92
+ </script>
93
+ <template>
94
+ <Text>Screen will not sleep</Text>
95
+ </template>
96
+ ```
97
+
98
+ ```ts
99
+ // Angular — examples/expo-angular/src/screens/KeepAwakeScreen.ts
100
+ import { Component, inject } from '@angular/core';
101
+ import { KeepAwakeService } from '@symbiote-native/keep-awake/angular';
102
+
103
+ @Component({ /* ... */ })
104
+ export class KeepAwakeScreen {
105
+ constructor() {
106
+ inject(KeepAwakeService).connect();
107
+ }
108
+ }
109
+ ```
110
+
111
+ ## API
112
+
113
+ ```ts
114
+ isAvailableAsync(): Promise<boolean> // keep-awake API availability on this device
115
+ activateKeepAwakeAsync(tag?: string): Promise<void> // acquires a lock under `tag` (default tag when omitted)
116
+ deactivateKeepAwake(tag?: string): Promise<void> // releases the lock under `tag` (default tag when omitted)
117
+ addListener(tagOrListener, listener?): EventSubscription // subscribes to keep-awake state changes
118
+ ```
119
+
120
+ Plus `ExpoKeepAwakeTag` (the shared default tag string), `KeepAwakeEvent`, `KeepAwakeListener`,
121
+ `KeepAwakeOptions` — ported from upstream's `KeepAwake.types.ts`. `KeepAwakeEvent#state` is kept
122
+ as a minimal `unknown` placeholder: upstream's own shape there is web-specific and has no native
123
+ analogue, and native listeners for it rarely fire.
124
+
125
+ ```ts
126
+ import { activateKeepAwakeAsync, deactivateKeepAwake } from '@symbiote-native/keep-awake';
127
+
128
+ // framework-scoped entry points re-export the same free functions, plus a lifecycle
129
+ // hook/composable/service:
130
+ import { useKeepAwake } from '@symbiote-native/keep-awake/react';
131
+ import { useKeepAwake } from '@symbiote-native/keep-awake/vue';
132
+ import { KeepAwakeService } from '@symbiote-native/keep-awake/angular';
133
+ ```
134
+
135
+ Each hook/composable/service activates a lock on mount (optionally registering `options.listener`
136
+ once activation resolves) and deactivates it on unmount — mirroring upstream's own
137
+ `useKeepAwake(tag?, options?)`.
138
+
139
+ ## Test it
140
+
141
+ No Fabric/Descriptor angle at all — keep-awake is a pure async-function + `EventEmitter` listener
142
+ surface, never a view. Tests inject a fake native-module object in place of the real
143
+ `requireNativeModule` resolution (`src/core/keep-awake.test.ts`,
144
+ `src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
145
+ `@symbiote-native/battery` and `@symbiote-native/device` use — no `installFabric()`-driven Fabric
146
+ assertions on the core level, only the adapter lifecycle tests mount through the fake Fabric slot
147
+ to prove activate-on-mount/deactivate-on-unmount. Native rendering itself is verified on-device —
148
+ see the parent [README](../../README.md).
@@ -0,0 +1,2 @@
1
+ export { KeepAwakeService } from './services/keep-awake.service';
2
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, type KeepAwakeEvent, type KeepAwakeListener, type KeepAwakeOptions, type EventSubscription, } from '../core';
@@ -0,0 +1,4 @@
1
+ // KeepAwakeService is the Angular-only lifecycle half; the free functions and event
2
+ // subscription plumbing all live in core, shared with React/Vue.
3
+ export { KeepAwakeService } from './services/keep-awake.service';
4
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
@@ -0,0 +1,5 @@
1
+ import { type KeepAwakeOptions } from '../../../core';
2
+ export declare class KeepAwakeService {
3
+ private readonly injector;
4
+ connect(tag?: string, options?: KeepAwakeOptions): void;
5
+ }
@@ -0,0 +1,83 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { effect, inject, Injectable, Injector } from '@angular/core';
36
+ import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
37
+ // Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
38
+ // LowPowerModeService (packages/battery) for the `connect()`/`effect()` pattern rationale — same
39
+ // wiring, but keep-awake has no value to surface as a Signal since it's a pure side effect for
40
+ // the component's lifetime. Angular has no useId equivalent either, so the default tag comes
41
+ // from the same monotonically-incrementing module-local counter the Vue composable uses.
42
+ //
43
+ // constructor() { inject(KeepAwakeService).connect(); }
44
+ let tagCounter = 0;
45
+ let KeepAwakeService = (() => {
46
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
47
+ let _classDescriptor;
48
+ let _classExtraInitializers = [];
49
+ let _classThis;
50
+ var KeepAwakeService = class {
51
+ static { _classThis = this; }
52
+ static {
53
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
54
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
55
+ KeepAwakeService = _classThis = _classDescriptor.value;
56
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
57
+ __runInitializers(_classThis, _classExtraInitializers);
58
+ }
59
+ injector = inject(Injector);
60
+ connect(tag, options) {
61
+ const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
62
+ effect(onCleanup => {
63
+ activateKeepAwakeAsync(tagOrDefault)
64
+ .then(() => {
65
+ if (options?.listener) {
66
+ addListener(tagOrDefault, options.listener);
67
+ }
68
+ })
69
+ .catch(() => { });
70
+ onCleanup(() => {
71
+ if (options?.suppressDeactivateWarnings) {
72
+ deactivateKeepAwake(tagOrDefault).catch(() => { });
73
+ }
74
+ else {
75
+ deactivateKeepAwake(tagOrDefault);
76
+ }
77
+ });
78
+ }, { injector: this.injector });
79
+ }
80
+ };
81
+ return KeepAwakeService = _classThis;
82
+ })();
83
+ export { KeepAwakeService };
@@ -0,0 +1,3 @@
1
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
2
+ export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions } from './types';
3
+ export type { EventSubscription } from 'expo-modules-core';
@@ -0,0 +1 @@
1
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
@@ -0,0 +1,17 @@
1
+ import { type EventSubscription } from 'expo-modules-core';
2
+ import type { KeepAwakeListener } from './types';
3
+ export declare const ExpoKeepAwakeTag = "ExpoKeepAwakeDefaultTag";
4
+ /** Resolves with whether the keep-awake API is available on this device. */
5
+ export declare function isAvailableAsync(): Promise<boolean>;
6
+ /**
7
+ * Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
8
+ * screen stays on for as long as any tag holds an active lock.
9
+ */
10
+ export declare function activateKeepAwakeAsync(tag?: string): Promise<void>;
11
+ /** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
12
+ export declare function deactivateKeepAwake(tag?: string): Promise<void>;
13
+ /**
14
+ * Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
15
+ * default tag, matching upstream's own `addListener` signature.
16
+ */
17
+ export declare function addListener(tagOrListener: string | KeepAwakeListener, listener?: KeepAwakeListener): EventSubscription;
@@ -0,0 +1,41 @@
1
+ // Hand-ported from .vendors/expo/packages/expo-keep-awake/src/index.ts (sdk-57, confirmed
2
+ // against origin/sdk-57 — the .vendors/expo working tree sits on `main` and differs
3
+ // cosmetically). Unlike battery (which falls back to a sentinel when a method is missing),
4
+ // upstream keep-awake throws from `addListener` when the native module lacks
5
+ // `addListenerForTag`, matching local-auth/haptics's UnavailabilityError convention.
6
+ import { UnavailabilityError } from 'expo-modules-core';
7
+ import { expoKeepAwake } from './native-module';
8
+ export const ExpoKeepAwakeTag = 'ExpoKeepAwakeDefaultTag';
9
+ /** Resolves with whether the keep-awake API is available on this device. */
10
+ export async function isAvailableAsync() {
11
+ if (expoKeepAwake.isAvailableAsync) {
12
+ return await expoKeepAwake.isAvailableAsync();
13
+ }
14
+ return true;
15
+ }
16
+ /**
17
+ * Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
18
+ * screen stays on for as long as any tag holds an active lock.
19
+ */
20
+ export async function activateKeepAwakeAsync(tag = ExpoKeepAwakeTag) {
21
+ await expoKeepAwake.activate?.(tag);
22
+ }
23
+ /** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
24
+ export async function deactivateKeepAwake(tag = ExpoKeepAwakeTag) {
25
+ await expoKeepAwake.deactivate?.(tag);
26
+ }
27
+ /**
28
+ * Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
29
+ * default tag, matching upstream's own `addListener` signature.
30
+ */
31
+ export function addListener(tagOrListener, listener) {
32
+ if (!expoKeepAwake.addListenerForTag) {
33
+ throw new UnavailabilityError('ExpoKeepAwake', 'addListenerForTag');
34
+ }
35
+ const tag = typeof tagOrListener === 'string' ? tagOrListener : ExpoKeepAwakeTag;
36
+ const resolvedListener = typeof tagOrListener === 'function' ? tagOrListener : listener;
37
+ if (!resolvedListener) {
38
+ throw new TypeError('addListener requires a listener function');
39
+ }
40
+ return expoKeepAwake.addListenerForTag(tag, resolvedListener);
41
+ }
@@ -0,0 +1,9 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+ import type { KeepAwakeListener } from './types';
3
+ export type INativeKeepAwakeModule = {
4
+ isAvailableAsync?(): Promise<boolean>;
5
+ activate?(tag: string): Promise<void>;
6
+ deactivate?(tag: string): Promise<void>;
7
+ addListenerForTag?(tag: string, listener: KeepAwakeListener): EventSubscription;
8
+ };
9
+ export declare const expoKeepAwake: INativeKeepAwakeModule;
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ const EXPO_KEEP_AWAKE_MODULE_NAME = 'ExpoKeepAwake';
3
+ export const expoKeepAwake = requireNativeModule(EXPO_KEEP_AWAKE_MODULE_NAME);
@@ -0,0 +1,8 @@
1
+ export type KeepAwakeEvent = {
2
+ state: unknown;
3
+ };
4
+ export type KeepAwakeListener = (event: KeepAwakeEvent) => void;
5
+ export type KeepAwakeOptions = {
6
+ listener?: KeepAwakeListener;
7
+ suppressDeactivateWarnings?: boolean;
8
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type KeepAwakeOptions } from '../../../core';
2
+ export declare function useKeepAwake(tag?: string, options?: KeepAwakeOptions): void;
@@ -0,0 +1,35 @@
1
+ // React lifecycle wiring over the framework-agnostic core (core/keep-awake.ts) — activates on
2
+ // mount, deactivates on unmount, mirroring upstream's own useKeepAwake. Uses React's useId for
3
+ // the default per-instance tag exactly like upstream, so two components calling useKeepAwake()
4
+ // concurrently without an explicit tag don't clobber each other's activation/deactivation.
5
+ //
6
+ // Upstream also checks the native module's own `addListenerForTag` presence directly before
7
+ // calling `addListener`; that private module isn't reachable from here (only core's public API
8
+ // is), so registering the listener just goes through the same promise chain — an
9
+ // UnavailabilityError from `addListener` is swallowed by the trailing `.catch(() => {})` exactly
10
+ // like a rejected `activateKeepAwakeAsync`, same net effect as upstream's own guard.
11
+ import { useEffect, useId } from 'react';
12
+ import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
13
+ export function useKeepAwake(tag, options) {
14
+ const defaultTag = useId();
15
+ const tagOrDefault = tag ?? defaultTag;
16
+ useEffect(() => {
17
+ let isMounted = true;
18
+ activateKeepAwakeAsync(tagOrDefault)
19
+ .then(() => {
20
+ if (isMounted && options?.listener) {
21
+ addListener(tagOrDefault, options.listener);
22
+ }
23
+ })
24
+ .catch(() => { });
25
+ return () => {
26
+ isMounted = false;
27
+ if (options?.suppressDeactivateWarnings) {
28
+ deactivateKeepAwake(tagOrDefault).catch(() => { });
29
+ }
30
+ else {
31
+ deactivateKeepAwake(tagOrDefault);
32
+ }
33
+ };
34
+ }, [tagOrDefault]);
35
+ }
@@ -0,0 +1,2 @@
1
+ export { useKeepAwake } from './hooks/use-keep-awake';
2
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, type KeepAwakeEvent, type KeepAwakeListener, type KeepAwakeOptions, type EventSubscription, } from '../core';
@@ -0,0 +1,5 @@
1
+ // @symbiote-native/keep-awake/react: the React entry over the framework-agnostic core. The
2
+ // lifecycle bucket is `hooks/` (never `composables/`, that's Vue's term) — see
3
+ // adapters/react/src/hooks for the same convention.
4
+ export { useKeepAwake } from './hooks/use-keep-awake';
5
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
@@ -0,0 +1,2 @@
1
+ import { type KeepAwakeOptions } from '../../../core';
2
+ export declare function useKeepAwake(tag?: string, options?: KeepAwakeOptions): void;
@@ -0,0 +1,28 @@
1
+ // Vue lifecycle wiring over the framework-agnostic core (core/keep-awake.ts) — activates on
2
+ // mount, deactivates on unmount, mirroring React's useKeepAwake hook. Vue has no useId
3
+ // equivalent, so the default tag comes from a small monotonically-incrementing module-local
4
+ // counter instead — simplest robust way to give each composable instance its own tag when the
5
+ // caller doesn't supply one.
6
+ import { onMounted, onUnmounted } from '@vue/runtime-core';
7
+ import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
8
+ let tagCounter = 0;
9
+ export function useKeepAwake(tag, options) {
10
+ const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
11
+ onMounted(() => {
12
+ activateKeepAwakeAsync(tagOrDefault)
13
+ .then(() => {
14
+ if (options?.listener) {
15
+ addListener(tagOrDefault, options.listener);
16
+ }
17
+ })
18
+ .catch(() => { });
19
+ });
20
+ onUnmounted(() => {
21
+ if (options?.suppressDeactivateWarnings) {
22
+ deactivateKeepAwake(tagOrDefault).catch(() => { });
23
+ }
24
+ else {
25
+ deactivateKeepAwake(tagOrDefault);
26
+ }
27
+ });
28
+ }
@@ -0,0 +1,2 @@
1
+ export { useKeepAwake } from './composables/use-keep-awake';
2
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, type KeepAwakeEvent, type KeepAwakeListener, type KeepAwakeOptions, type EventSubscription, } from '../core';
@@ -0,0 +1,5 @@
1
+ // @symbiote-native/keep-awake/vue: the Vue entry over the framework-agnostic core. The
2
+ // lifecycle bucket is `composables/` (never `hooks/`, that's React's term) — see
3
+ // adapters/vue/src/composables for the same convention.
4
+ export { useKeepAwake } from './composables/use-keep-awake';
5
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
@@ -0,0 +1,2 @@
1
+ export { KeepAwakeService } from './services/keep-awake.service';
2
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, type KeepAwakeEvent, type KeepAwakeListener, type KeepAwakeOptions, type EventSubscription, } from '../core';
@@ -0,0 +1,5 @@
1
+ // KeepAwakeService is the Angular-only lifecycle half; the free functions and event
2
+ // subscription plumbing all live in core, shared with React/Vue.
3
+ export { KeepAwakeService } from './services/keep-awake.service';
4
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from '../core';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,iEAAiE;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,GAKZ,MAAM,SAAS,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type KeepAwakeOptions } from '../../../core';
2
+ import * as i0 from "@angular/core";
3
+ export declare class KeepAwakeService {
4
+ private readonly injector;
5
+ connect(tag?: string, options?: KeepAwakeOptions): void;
6
+ static ɵfac: i0.ɵɵFactoryDeclaration<KeepAwakeService, never>;
7
+ static ɵprov: i0.ɵɵInjectableDeclaration<KeepAwakeService>;
8
+ }
@@ -0,0 +1,41 @@
1
+ import { effect, inject, Injectable, Injector } from '@angular/core';
2
+ import { activateKeepAwakeAsync, addListener, deactivateKeepAwake, } from '../../../core';
3
+ import * as i0 from "@angular/core";
4
+ // Angular twin of React's `useKeepAwake` hook and Vue's `useKeepAwake` composable. See
5
+ // LowPowerModeService (packages/battery) for the `connect()`/`effect()` pattern rationale — same
6
+ // wiring, but keep-awake has no value to surface as a Signal since it's a pure side effect for
7
+ // the component's lifetime. Angular has no useId equivalent either, so the default tag comes
8
+ // from the same monotonically-incrementing module-local counter the Vue composable uses.
9
+ //
10
+ // constructor() { inject(KeepAwakeService).connect(); }
11
+ let tagCounter = 0;
12
+ export class KeepAwakeService {
13
+ injector = inject(Injector);
14
+ connect(tag, options) {
15
+ const tagOrDefault = tag ?? `keep-awake-tag-${++tagCounter}`;
16
+ effect(onCleanup => {
17
+ activateKeepAwakeAsync(tagOrDefault)
18
+ .then(() => {
19
+ if (options?.listener) {
20
+ addListener(tagOrDefault, options.listener);
21
+ }
22
+ })
23
+ .catch(() => { });
24
+ onCleanup(() => {
25
+ if (options?.suppressDeactivateWarnings) {
26
+ deactivateKeepAwake(tagOrDefault).catch(() => { });
27
+ }
28
+ else {
29
+ deactivateKeepAwake(tagOrDefault);
30
+ }
31
+ });
32
+ }, { injector: this.injector });
33
+ }
34
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: KeepAwakeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
35
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: KeepAwakeService, providedIn: 'root' });
36
+ }
37
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: KeepAwakeService, decorators: [{
38
+ type: Injectable,
39
+ args: [{ providedIn: 'root' }]
40
+ }] });
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/keep-awake.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,mBAAmB,GAEpB,MAAM,eAAe,CAAC;;AAEvB,uFAAuF;AACvF,iGAAiG;AACjG,+FAA+F;AAC/F,6FAA6F;AAC7F,yFAAyF;AACzF,EAAE;AACF,0DAA0D;AAC1D,IAAI,UAAU,GAAG,CAAC,CAAC;AAGnB,MAAM,OAAO,gBAAgB;IACV,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO,CAAC,GAAY,EAAE,OAA0B;QAC9C,MAAM,YAAY,GAAG,GAAG,IAAI,kBAAkB,EAAE,UAAU,EAAE,CAAC;QAE7D,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,sBAAsB,CAAC,YAAY,CAAC;iBACjC,IAAI,CAAC,GAAG,EAAE;gBACT,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;oBACtB,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAEnB,SAAS,CAAC,GAAG,EAAE;gBACb,IAAI,OAAO,EAAE,0BAA0B,EAAE,CAAC;oBACxC,mBAAmB,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,mBAAmB,CAAC,YAAY,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;IACJ,CAAC;uGA1BU,gBAAgB;2GAAhB,gBAAgB,cADH,MAAM;;2FACnB,gBAAgB;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
@@ -0,0 +1,3 @@
1
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
2
+ export type { KeepAwakeEvent, KeepAwakeListener, KeepAwakeOptions } from './types';
3
+ export type { EventSubscription } from 'expo-modules-core';
@@ -0,0 +1,2 @@
1
+ export { ExpoKeepAwakeTag, isAvailableAsync, activateKeepAwakeAsync, deactivateKeepAwake, addListener, } from './keep-awake';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,GACZ,MAAM,cAAc,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type EventSubscription } from 'expo-modules-core';
2
+ import type { KeepAwakeListener } from './types';
3
+ export declare const ExpoKeepAwakeTag = "ExpoKeepAwakeDefaultTag";
4
+ /** Resolves with whether the keep-awake API is available on this device. */
5
+ export declare function isAvailableAsync(): Promise<boolean>;
6
+ /**
7
+ * Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
8
+ * screen stays on for as long as any tag holds an active lock.
9
+ */
10
+ export declare function activateKeepAwakeAsync(tag?: string): Promise<void>;
11
+ /** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
12
+ export declare function deactivateKeepAwake(tag?: string): Promise<void>;
13
+ /**
14
+ * Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
15
+ * default tag, matching upstream's own `addListener` signature.
16
+ */
17
+ export declare function addListener(tagOrListener: string | KeepAwakeListener, listener?: KeepAwakeListener): EventSubscription;
@@ -0,0 +1,42 @@
1
+ // Hand-ported from .vendors/expo/packages/expo-keep-awake/src/index.ts (sdk-57, confirmed
2
+ // against origin/sdk-57 — the .vendors/expo working tree sits on `main` and differs
3
+ // cosmetically). Unlike battery (which falls back to a sentinel when a method is missing),
4
+ // upstream keep-awake throws from `addListener` when the native module lacks
5
+ // `addListenerForTag`, matching local-auth/haptics's UnavailabilityError convention.
6
+ import { UnavailabilityError } from 'expo-modules-core';
7
+ import { expoKeepAwake } from './native-module';
8
+ export const ExpoKeepAwakeTag = 'ExpoKeepAwakeDefaultTag';
9
+ /** Resolves with whether the keep-awake API is available on this device. */
10
+ export async function isAvailableAsync() {
11
+ if (expoKeepAwake.isAvailableAsync) {
12
+ return await expoKeepAwake.isAvailableAsync();
13
+ }
14
+ return true;
15
+ }
16
+ /**
17
+ * Activates a keep-awake lock under `tag` (the shared default tag when none is given) — the
18
+ * screen stays on for as long as any tag holds an active lock.
19
+ */
20
+ export async function activateKeepAwakeAsync(tag = ExpoKeepAwakeTag) {
21
+ await expoKeepAwake.activate?.(tag);
22
+ }
23
+ /** Releases the keep-awake lock held under `tag` (the shared default tag when none is given). */
24
+ export async function deactivateKeepAwake(tag = ExpoKeepAwakeTag) {
25
+ await expoKeepAwake.deactivate?.(tag);
26
+ }
27
+ /**
28
+ * Subscribes to keep-awake state changes for a tag. Overloaded to accept a bare listener for the
29
+ * default tag, matching upstream's own `addListener` signature.
30
+ */
31
+ export function addListener(tagOrListener, listener) {
32
+ if (!expoKeepAwake.addListenerForTag) {
33
+ throw new UnavailabilityError('ExpoKeepAwake', 'addListenerForTag');
34
+ }
35
+ const tag = typeof tagOrListener === 'string' ? tagOrListener : ExpoKeepAwakeTag;
36
+ const resolvedListener = typeof tagOrListener === 'function' ? tagOrListener : listener;
37
+ if (!resolvedListener) {
38
+ throw new TypeError('addListener requires a listener function');
39
+ }
40
+ return expoKeepAwake.addListenerForTag(tag, resolvedListener);
41
+ }
42
+ //# sourceMappingURL=keep-awake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keep-awake.js","sourceRoot":"","sources":["../../src/core/keep-awake.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,oFAAoF;AACpF,2FAA2F;AAC3F,6EAA6E;AAC7E,qFAAqF;AACrF,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAE1D,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,aAAa,CAAC,gBAAgB,EAAE,CAAC;QACnC,OAAO,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAc,gBAAgB;IACzE,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAc,gBAAgB;IACtE,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,aAAyC,EACzC,QAA4B;IAE5B,IAAI,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACjF,MAAM,gBAAgB,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxF,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,aAAa,CAAC,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+ import type { KeepAwakeListener } from './types';
3
+ export type INativeKeepAwakeModule = {
4
+ isAvailableAsync?(): Promise<boolean>;
5
+ activate?(tag: string): Promise<void>;
6
+ deactivate?(tag: string): Promise<void>;
7
+ addListenerForTag?(tag: string, listener: KeepAwakeListener): EventSubscription;
8
+ };
9
+ export declare const expoKeepAwake: INativeKeepAwakeModule;
@@ -0,0 +1,4 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ const EXPO_KEEP_AWAKE_MODULE_NAME = 'ExpoKeepAwake';
3
+ export const expoKeepAwake = requireNativeModule(EXPO_KEEP_AWAKE_MODULE_NAME);
4
+ //# sourceMappingURL=native-module.js.map