@symbiote-native/task-manager 0.1.2 → 0.1.3

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 (2) hide show
  1. package/README.md +47 -29
  2. package/package.json +15 -15
package/README.md CHANGED
@@ -1,18 +1,19 @@
1
1
  # @symbiote-native/task-manager
2
2
 
3
- A wrapper package for [SymbioteNative](../../README.md) that makes
4
- [`expo-task-manager`](https://github.com/expo/expo/tree/main/packages/expo-task-manager)
5
- usable from **every** adapter — React, Vue, Svelte, Solid, and Angular. Like
6
- [`@symbiote-native/local-auth`](../local-auth), every export is a plain function or a one-time
7
- module-load side effect, so there is no hook/composable/service to wrap: the React, Vue, Svelte,
8
- Solid, and Angular entry points are plain re-exports of the same `core`.
3
+ Run your code when the OS wakes the app in the background: a location update, a geofence event, a
4
+ periodic sync, a silent push. One API for every [SymbioteNative](../../README.md) adapter (React,
5
+ Vue, Svelte, Solid and Angular).
6
+
7
+ It wraps [`expo-task-manager`](https://github.com/expo/expo/tree/main/packages/expo-task-manager).
8
+ Like [`@symbiote-native/local-auth`](../local-auth), every export is a plain function or a one-time
9
+ module-load side effect, so there is no hook, composable or service to wrap: every adapter entry
10
+ point is a plain re-export of the same `core`.
9
11
 
10
12
  This package is the low-level primitive other background-work packages register tasks through
11
- (background location, geofencing, background notification delivery) — it does **not** itself
12
- schedule anything. It defines tasks, tracks which are registered, dispatches native's
13
- task-execute event to the matching executor, and acks completion. Starting a task running (e.g.
14
- periodic scheduling, geofence triggers) is each consumer's own job, done through its own native
15
- module.
13
+ (background location, geofencing, background notification delivery). It does **not** itself
14
+ schedule anything: it defines tasks, tracks which are registered, dispatches native's task-execute
15
+ event to the matching executor, and acks completion. Starting a task running (periodic scheduling,
16
+ geofence triggers) is each consumer's own job, done through its own native module.
16
17
 
17
18
  ## Install
18
19
 
@@ -29,31 +30,31 @@ npx @symbiote-native/cli add --task-manager
29
30
  ```
30
31
 
31
32
  Either way: installs `@symbiote-native/task-manager` and wires the native autolinking
32
- automatically — see [`@symbiote-native/cli`](../cli). Most apps get this transitively anyway, pulled in by
33
+ automatically - see [`@symbiote-native/cli`](../cli). Most apps get this transitively anyway, pulled in by
33
34
  `--location`/`--audio`/`--background-fetch`/`--background-task`/`--notifications`.
34
35
 
35
36
  <details>
36
- <summary>Manual install (no CLI — installing and wiring native autolinking by hand)</summary>
37
+ <summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
37
38
 
38
39
  ```bash
39
40
  npm install @symbiote-native/task-manager
40
41
  ```
41
42
 
42
43
  `expo-task-manager`, `unimodules-app-loader`, and `expo-modules-core` come along as regular
43
- dependencies, pinned to exact versions — never install them yourself, and never add the `expo`
44
+ dependencies, pinned to exact versions - never install them yourself, and never add the `expo`
44
45
  meta-package to your project.
45
46
 
46
47
  ## Required one-time step: native autolinking wiring
47
48
 
48
- Same one-time step as every other `expo-modules-core` package this project ships — see
49
+ Same one-time step as every other `expo-modules-core` package this project ships - see
49
50
  [`@symbiote-native/local-auth`'s README](../local-auth/README.md#required-one-time-step-native-autolinking-wiring)
50
51
  and the `symbiote-expo-native-module` project skill. Android's headless-boot loader
51
52
  (`RNHeadlessAppLoader`) and iOS's `TaskManagerAppDelegateSubscriber` are both discovered
52
- automatically by Expo's own autolinking the moment this package is installed — no extra
53
+ automatically by Expo's own autolinking the moment this package is installed - no extra
53
54
  `native-link.json` entry, no app-level edit.
54
55
 
55
56
  One iOS `Info.plist` key IS wired: `UIBackgroundModes: fetch`
56
- (`native-link.json`'s `ios.infoPlistArrayKeys`) — upstream's own `withTaskManager.ts` config
57
+ (`native-link.json`'s `ios.infoPlistArrayKeys`) - upstream's own `withTaskManager.ts` config
57
58
  plugin adds this unconditionally, as the baseline mode any registered task's background delivery
58
59
  relies on, independent of which consumer package (`background-fetch`, `location`, …) actually
59
60
  registers a task. `@symbiote-native/expo-modules-link` merges it into the same array those
@@ -68,8 +69,8 @@ src/core/ defineTask / isTaskDefined / isTaskRegisteredAsync / getTaskOption
68
69
  getRegisteredTasksAsync / unregisterTaskAsync / unregisterAllTasksAsync /
69
70
  isAvailableAsync, plus the task-body/executor types. native-module.ts resolves the
70
71
  native module via expo-modules-core's requireNativeModule and wires one listener at
71
- module load — native invokes it whenever a defined task should run.
72
- src/angular/ @symbiote-native/task-manager/angular — export * from '../core'
72
+ module load - native invokes it whenever a defined task should run.
73
+ src/angular/ @symbiote-native/task-manager/angular - export * from '../core'
73
74
  ```
74
75
 
75
76
  `./react`, `./vue`, `./svelte`, and `./solid` are `exports`-map aliases straight onto
@@ -78,12 +79,12 @@ src/angular/ @symbiote-native/task-manager/angular — export * from '../core'
78
79
 
79
80
  ## Use it
80
81
 
81
- `defineTask` must run at the top of the JS bundle, outside any component — the app can be
82
+ `defineTask` must run at the top of the JS bundle, outside any component - the app can be
82
83
  launched headlessly to run a background task, with no views mounted, so a task defined inside a
83
84
  component lifecycle method would simply never register on that launch.
84
85
 
85
86
  ```ts
86
- // index.ts, alongside AppRegistry.registerComponent — identical on every adapter
87
+ // index.ts, alongside AppRegistry.registerComponent - identical on every adapter
87
88
  import { defineTask } from '@symbiote-native/task-manager';
88
89
 
89
90
  const SYNC_TASK = 'background-sync';
@@ -97,7 +98,7 @@ defineTask(SYNC_TASK, async ({ data, error }) => {
97
98
  });
98
99
  ```
99
100
 
100
- A consumer registers the task with native through its own native module —
101
+ A consumer registers the task with native through its own native module -
101
102
  [`@symbiote-native/location`](../location)'s `startLocationUpdatesAsync`/`startGeofencingAsync`,
102
103
  [`@symbiote-native/background-fetch`](../background-fetch)'s `registerTaskAsync`,
103
104
  [`@symbiote-native/background-task`](../background-task)'s `registerTaskAsync`, or
@@ -116,7 +117,7 @@ const tasks = await getRegisteredTasksAsync();
116
117
  await unregisterTaskAsync(SYNC_TASK); // stop receiving updates for this task
117
118
  ```
118
119
 
119
- Identical import surface on every adapter — `@symbiote-native/task-manager/react`,
120
+ Identical import surface on every adapter - `@symbiote-native/task-manager/react`,
120
121
  `/vue`, `/svelte`, `/solid`, `/angular` all re-export the same functions.
121
122
 
122
123
  ## API
@@ -133,16 +134,16 @@ isAvailableAsync(): Promise<boolean>
133
134
  ```
134
135
 
135
136
  Plus `ITaskManagerError`, `ITaskManagerTask`, `ITaskManagerTaskBody`,
136
- `ITaskManagerTaskBodyExecutionInfo`, `ITaskManagerTaskExecutor` — ported from upstream's
137
+ `ITaskManagerTaskBodyExecutionInfo`, `ITaskManagerTaskExecutor` - ported from upstream's
137
138
  `TaskManager.ts`, renamed with this repo's `I`-prefix convention for exported types
138
- (`ts-js-best-practices`). Unlike upstream, there is no `registerTaskAsync` free function here —
139
+ (`ts-js-best-practices`). Unlike upstream, there is no `registerTaskAsync` free function here -
139
140
  upstream never exposes one either; registration is always driven by the consumer that needs the
140
141
  task (`@symbiote-native/location`, `@symbiote-native/background-fetch`,
141
142
  `@symbiote-native/background-task`, `@symbiote-native/notifications`).
142
143
 
143
144
  ## Notes
144
145
 
145
- - **`isAvailableAsync` resolves `false` rather than throwing when the native method is missing** —
146
+ - **`isAvailableAsync` resolves `false` rather than throwing when the native method is missing** -
146
147
  every other guarded function throws an `UnavailabilityError`. This matches upstream's own
147
148
  contract: "can this API be used at all" has to answer even where the rest of the surface can't.
148
149
  - **A defined task that native fires but nobody registered still gets acked and unregistered.**
@@ -153,12 +154,29 @@ task (`@symbiote-native/location`, `@symbiote-native/background-fetch`,
153
154
  `notifyTaskFinishedAsync` always fires in a `finally`, so a bug in one task's executor can't
154
155
  leave the OS believing the task never completed.
155
156
 
157
+ ## Common questions
158
+
159
+ - **My task never runs.** Run `defineTask` at the top of the bundle, outside any component, before
160
+ anything registers it (registering an undefined task throws); and make sure a consumer package
161
+ registered it, since `defineTask` schedules nothing.
162
+ - **Stops when the app is swiped away.** iOS terminates it; on Android recents removal varies by
163
+ vendor.
164
+ - **Stops after 5 to 10 minutes on Android.** Doze mode: use a foreground service for continuous work.
165
+ - **Works in debug, not release.** Test release builds early on Android.
166
+ - **Simulators.** Use a physical device; the iOS Simulator has no background task scheduler.
167
+
168
+ Sources: [Expo docs: BackgroundTask](https://docs.expo.dev/versions/latest/sdk/background-task/),
169
+ [expo/expo#9570](https://github.com/expo/expo/issues/9570),
170
+ [expo/expo#3535](https://github.com/expo/expo/issues/3535),
171
+ [expo/expo#14076](https://github.com/expo/expo/issues/14076),
172
+ [expo/expo#26717](https://github.com/expo/expo/issues/26717).
173
+
156
174
  ## Test it
157
175
 
158
- No Fabric/Descriptor angle at all — every function here is a pure async-function surface plus one
176
+ No Fabric/Descriptor angle at all - every function here is a pure async-function surface plus one
159
177
  module-load event listener, never a view or per-instance state. Tests inject a fake native-module
160
178
  object in place of the real `requireNativeModule` resolution and fire the wired listener directly
161
- (`src/core/task-manager.test.ts`) — no `installFabric()`, no ViewConfig. The headless-relaunch
179
+ (`src/core/task-manager.test.ts`) - no `installFabric()`, no ViewConfig. The headless-relaunch
162
180
  mechanics themselves (native tearing down and re-executing the whole JS bundle with no UI mounted)
163
- are OS-level and can only be verified on a real device — see the `symbiote-expo-native-module`
181
+ are OS-level and can only be verified on a real device - see the `symbiote-expo-native-module`
164
182
  skill §10e for what's traced from source versus still unverified.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/task-manager",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "expo-task-manager wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Defines and tracks background tasks that native code invokes headlessly.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -72,7 +72,7 @@
72
72
  "expo-task-manager": "57.0.15",
73
73
  "unimodules-app-loader": "57.0.1",
74
74
  "expo-constants": "57.0.19",
75
- "expo-modules-core": "57.0.5"
75
+ "expo-modules-core": "57.0.20"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "@angular/core": ">=20",
@@ -82,12 +82,12 @@
82
82
  "solid-js": ">=1.9.0",
83
83
  "svelte": ">=5.56.0",
84
84
  "vue": ">=3.5.0",
85
- "@symbiote-native/angular": "^3.1.2",
86
- "@symbiote-native/engine": "^1.3.1",
87
- "@symbiote-native/react": "^3.0.4",
88
- "@symbiote-native/solid": "^3.0.4",
89
- "@symbiote-native/svelte": "^3.0.4",
90
- "@symbiote-native/vue": "^3.0.4"
85
+ "@symbiote-native/angular": "^3.2.0",
86
+ "@symbiote-native/engine": "^1.5.0",
87
+ "@symbiote-native/react": "^3.2.0",
88
+ "@symbiote-native/solid": "^3.1.0",
89
+ "@symbiote-native/svelte": "^3.1.0",
90
+ "@symbiote-native/vue": "^3.2.0"
91
91
  },
92
92
  "peerDependenciesMeta": {
93
93
  "@symbiote-native/angular": {
@@ -135,13 +135,13 @@
135
135
  "solid-js": "^1.9.14",
136
136
  "svelte": "^5.56.0",
137
137
  "typescript": "~6.0.0",
138
- "@symbiote-native/angular": "3.1.2",
139
- "@symbiote-native/engine": "1.3.1",
140
- "@symbiote-native/react": "3.0.4",
141
- "@symbiote-native/solid": "3.0.4",
142
- "@symbiote-native/svelte": "3.0.4",
143
- "@symbiote-native/test-utils": "0.4.4",
144
- "@symbiote-native/vue": "3.0.4"
138
+ "@symbiote-native/angular": "3.2.0",
139
+ "@symbiote-native/engine": "1.5.0",
140
+ "@symbiote-native/react": "3.2.0",
141
+ "@symbiote-native/solid": "3.1.0",
142
+ "@symbiote-native/svelte": "3.1.0",
143
+ "@symbiote-native/test-utils": "0.4.6",
144
+ "@symbiote-native/vue": "3.2.0"
145
145
  },
146
146
  "scripts": {
147
147
  "typecheck": "tsc --build",