@elizaos/capacitor-appblocker 2.0.0-beta.1 → 2.0.3-beta.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.
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/android/build.gradle +8 -0
- package/android/src/main/java/ai/eliza/plugins/appblocker/AppBlockerPlugin.kt +30 -0
- package/dist/esm/backend.d.ts +46 -0
- package/dist/esm/backend.d.ts.map +1 -0
- package/dist/esm/backend.js +50 -0
- package/dist/esm/backend.js.map +1 -0
- package/dist/esm/backend.test.d.ts +2 -0
- package/dist/esm/backend.test.d.ts.map +1 -0
- package/dist/esm/backend.test.js +112 -0
- package/dist/esm/backend.test.js.map +1 -0
- package/dist/esm/definitions.d.ts +19 -0
- package/dist/esm/definitions.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +1 -1
- package/dist/esm/web.d.ts.map +1 -1
- package/dist/esm/web.js +65 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/esm/web.test.d.ts +2 -0
- package/dist/esm/web.test.d.ts.map +1 -0
- package/dist/esm/web.test.js +49 -0
- package/dist/esm/web.test.js.map +1 -0
- package/dist/plugin.cjs.js +116 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +116 -1
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/AppBlockerPlugin/AppBlockerPlugin.swift +28 -2
- package/package.json +13 -9
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shaw Walters and elizaOS Contributors
|
|
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,87 @@
|
|
|
1
|
+
# @elizaos/capacitor-appblocker
|
|
2
|
+
|
|
3
|
+
A Capacitor plugin that blocks selected apps on **Android** (Usage Access + system overlay) and **iOS** (Family Controls + ManagedSettings). Not available in browsers.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
The plugin lets a Capacitor-based Eliza agent app:
|
|
8
|
+
|
|
9
|
+
- Check and request the OS permissions required for blocking.
|
|
10
|
+
- Present the user with a system-level app picker to choose which apps to block.
|
|
11
|
+
- Apply or lift an app block, optionally with a time limit (Android) or indefinitely (iOS).
|
|
12
|
+
- Query the current blocking status and engine details.
|
|
13
|
+
|
|
14
|
+
### Platform engines
|
|
15
|
+
|
|
16
|
+
| Platform | Engine | Notes |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Android | Usage Access + system overlay | A foreground service polls foreground events every 500 ms and shows a full-screen shield when a blocked app is detected. |
|
|
19
|
+
| iOS | Family Controls + ManagedSettings | `ManagedSettingsStore` shields selected apps. Timed blocks require a DeviceActivity extension; this package currently supports indefinite iOS blocks only. |
|
|
20
|
+
| Browser | None | Permission checks return `status: "not-applicable"`, `getStatus` returns `status: "unavailable"`, mutations return `success: false`, list methods return empty arrays. |
|
|
21
|
+
|
|
22
|
+
## API
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { AppBlocker } from "@elizaos/capacitor-appblocker";
|
|
26
|
+
|
|
27
|
+
// Check whether OS permissions are already granted
|
|
28
|
+
const perm = await AppBlocker.checkPermissions();
|
|
29
|
+
|
|
30
|
+
// Request missing permissions (opens system settings or triggers Family Controls auth)
|
|
31
|
+
await AppBlocker.requestPermissions();
|
|
32
|
+
|
|
33
|
+
// Android: get a list of installed launcher apps
|
|
34
|
+
const { apps } = await AppBlocker.getInstalledApps();
|
|
35
|
+
|
|
36
|
+
// iOS: opens FamilyActivityPicker and returns selected apps with tokenData.
|
|
37
|
+
// Android: returns immediately with { apps: [], cancelled: true } — use getInstalledApps() instead.
|
|
38
|
+
const { apps: selected, cancelled } = await AppBlocker.selectApps();
|
|
39
|
+
|
|
40
|
+
// Block apps — pass packageNames (Android) or appTokens (iOS)
|
|
41
|
+
const result = await AppBlocker.blockApps({
|
|
42
|
+
packageNames: ["com.instagram.android"],
|
|
43
|
+
durationMinutes: 60, // omit for indefinite; not supported on iOS
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Remove all active blocks
|
|
47
|
+
await AppBlocker.unblockApps();
|
|
48
|
+
|
|
49
|
+
// Get current blocking state
|
|
50
|
+
const status = await AppBlocker.getStatus();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Full TypeScript types are exported from the package root: `AppBlockerPlugin`, `AppBlockerStatus`, `AppBlockerPermissionResult`, `BlockAppsOptions`, `InstalledApp`, `SelectAppsResult`, `UnblockAppsResult`, `AppBlockerCapabilities`.
|
|
54
|
+
|
|
55
|
+
## Required permissions
|
|
56
|
+
|
|
57
|
+
### Android
|
|
58
|
+
|
|
59
|
+
The consuming app's `AndroidManifest.xml` inherits these declarations from the plugin:
|
|
60
|
+
|
|
61
|
+
- `PACKAGE_USAGE_STATS` — Usage Access (user must grant via Settings).
|
|
62
|
+
- `SYSTEM_ALERT_WINDOW` — Draw Over Other Apps (user must grant via Settings).
|
|
63
|
+
- `FOREGROUND_SERVICE` + `FOREGROUND_SERVICE_SPECIAL_USE` — required for the monitoring service.
|
|
64
|
+
- `POST_NOTIFICATIONS` — for the persistent "App Blocker Active" notification.
|
|
65
|
+
|
|
66
|
+
Use `checkPermissions()` / `requestPermissions()` to guide the user through granting both.
|
|
67
|
+
|
|
68
|
+
### iOS
|
|
69
|
+
|
|
70
|
+
The app must have the `com.apple.developer.family-controls` entitlement in its provisioning profile. Call `requestPermissions()` to trigger the system authorization sheet. Requires iOS 15.0+.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm install @elizaos/capacitor-appblocker
|
|
76
|
+
npx cap sync
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For iOS, add the pod to your `Podfile` (Capacitor's sync does this automatically) and ensure your Xcode target has the Family Controls entitlement enabled.
|
|
80
|
+
|
|
81
|
+
## Building from source
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bun run --cwd plugins/plugin-native-appblocker build
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Produces `dist/esm/` (ESM), `dist/plugin.js` (IIFE/CDN), and `dist/plugin.cjs.js` (CJS).
|
package/android/build.gradle
CHANGED
|
@@ -7,6 +7,11 @@ ext {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
apply plugin: 'com.android.library'
|
|
10
|
+
// Apply the Kotlin Android plugin so the plugin's .kt class is bundled into the
|
|
11
|
+
// library AAR. Without it AGP's built-in kotlinc compiles the sources but does
|
|
12
|
+
// NOT bundle the .class files, so the Capacitor plugin class is absent from the
|
|
13
|
+
// app dex at runtime (PluginLoadException -> the whole plugin set fails to load).
|
|
14
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
10
15
|
android {
|
|
11
16
|
namespace = "ai.eliza.plugins.appblocker"
|
|
12
17
|
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
|
|
@@ -28,6 +33,9 @@ android {
|
|
|
28
33
|
sourceCompatibility JavaVersion.VERSION_17
|
|
29
34
|
targetCompatibility JavaVersion.VERSION_17
|
|
30
35
|
}
|
|
36
|
+
kotlinOptions {
|
|
37
|
+
jvmTarget = "17"
|
|
38
|
+
}
|
|
31
39
|
|
|
32
40
|
}
|
|
33
41
|
|
|
@@ -178,14 +178,19 @@ class AppBlockerPlugin : Plugin() {
|
|
|
178
178
|
|
|
179
179
|
call.resolve(
|
|
180
180
|
JSObject().apply {
|
|
181
|
+
put("status", if (saved != null) "active" else "inactive")
|
|
181
182
|
put("available", true)
|
|
182
183
|
put("active", saved != null)
|
|
183
184
|
put("platform", "android")
|
|
184
185
|
put("engine", "usage-stats-overlay")
|
|
186
|
+
put("capabilities", appBlockerCapabilities())
|
|
185
187
|
put("blockedCount", saved?.packageNames?.size ?: 0)
|
|
186
188
|
put("blockedPackageNames", JSArray(saved?.packageNames ?: emptyList<String>()))
|
|
187
189
|
put("endsAt", saved?.endsAtEpochMs?.let { Instant.ofEpochMilli(it).toString() })
|
|
188
190
|
put("permissionStatus", permission.getString("status"))
|
|
191
|
+
put("canRequest", permission.getBool("canRequest"))
|
|
192
|
+
put("canOpenSettings", permission.getBool("canOpenSettings"))
|
|
193
|
+
put("settingsTarget", permission.opt("settingsTarget"))
|
|
189
194
|
if (!reason.isNullOrBlank()) {
|
|
190
195
|
put("reason", reason)
|
|
191
196
|
}
|
|
@@ -209,10 +214,35 @@ class AppBlockerPlugin : Plugin() {
|
|
|
209
214
|
return JSObject().apply {
|
|
210
215
|
put("status", if (usageAccess && overlayAccess) "granted" else "not-determined")
|
|
211
216
|
put("canRequest", !usageAccess || !overlayAccess)
|
|
217
|
+
put("canOpenSettings", !usageAccess || !overlayAccess)
|
|
218
|
+
put("settingsTarget", settingsTarget(usageAccess, overlayAccess))
|
|
219
|
+
put("engine", "usage-stats-overlay")
|
|
220
|
+
put("capabilities", appBlockerCapabilities())
|
|
212
221
|
missingPermissionReason()?.let { put("reason", it) }
|
|
213
222
|
}
|
|
214
223
|
}
|
|
215
224
|
|
|
225
|
+
private fun appBlockerCapabilities(): JSObject {
|
|
226
|
+
return JSObject().apply {
|
|
227
|
+
put("canSelectApps", true)
|
|
228
|
+
put("canBlockApps", true)
|
|
229
|
+
put("canScheduleTimedBlocks", true)
|
|
230
|
+
put("canUnblockEarly", true)
|
|
231
|
+
put("requiresFamilyControls", false)
|
|
232
|
+
put("requiresUsageAccess", true)
|
|
233
|
+
put("requiresOverlay", true)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private fun settingsTarget(usageAccess: Boolean, overlayAccess: Boolean): String? {
|
|
238
|
+
return when {
|
|
239
|
+
!usageAccess && !overlayAccess -> "deviceSettings"
|
|
240
|
+
!usageAccess -> "usageAccess"
|
|
241
|
+
!overlayAccess -> "overlay"
|
|
242
|
+
else -> null
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
216
246
|
private fun missingPermissionReason(): String? {
|
|
217
247
|
val missingUsageAccess = !hasUsageAccess()
|
|
218
248
|
val missingOverlayAccess = !canDrawOverlays()
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter that exposes the Capacitor `ElizaAppBlocker` plugin as the
|
|
3
|
+
* `NativeAppBlockerBackend` the `@elizaos/plugin-blocker` app-blocker engine
|
|
4
|
+
* dispatches to. Registering the result with `registerNativeAppBlockerBackend`
|
|
5
|
+
* makes the engine drive the real native enforcement (Family Controls on iOS,
|
|
6
|
+
* Usage-Stats + overlay on Android).
|
|
7
|
+
*
|
|
8
|
+
* Process boundary: this adapter only reaches the native plugin when it runs in
|
|
9
|
+
* the same JS realm as Capacitor (the WebView / web build).
|
|
10
|
+
*/
|
|
11
|
+
import type { AppBlockerPlugin, BlockAppsOptions, BlockAppsResult, InstalledApp, SelectAppsResult, UnblockAppsResult } from "./definitions";
|
|
12
|
+
interface BackendAppBlockerStatus {
|
|
13
|
+
available: boolean;
|
|
14
|
+
active: boolean;
|
|
15
|
+
platform: string;
|
|
16
|
+
engine: "family-controls" | "usage-stats-overlay" | "none";
|
|
17
|
+
blockedCount: number;
|
|
18
|
+
blockedPackageNames: string[];
|
|
19
|
+
endsAt: string | null;
|
|
20
|
+
permissionStatus: "granted" | "denied" | "not-determined" | "not-applicable";
|
|
21
|
+
reason?: string;
|
|
22
|
+
}
|
|
23
|
+
interface BackendAppBlockerPermissionResult {
|
|
24
|
+
status: "granted" | "denied" | "not-determined" | "not-applicable";
|
|
25
|
+
canRequest: boolean;
|
|
26
|
+
reason?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface NativeAppBlockerBackend {
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
checkPermissions(): Promise<BackendAppBlockerPermissionResult>;
|
|
31
|
+
requestPermissions(): Promise<BackendAppBlockerPermissionResult>;
|
|
32
|
+
getInstalledApps(): Promise<{
|
|
33
|
+
apps: InstalledApp[];
|
|
34
|
+
}>;
|
|
35
|
+
selectApps(): Promise<SelectAppsResult>;
|
|
36
|
+
blockApps(options: BlockAppsOptions): Promise<BlockAppsResult>;
|
|
37
|
+
unblockApps(): Promise<UnblockAppsResult>;
|
|
38
|
+
getStatus(): Promise<BackendAppBlockerStatus>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Wrap an `AppBlockerPlugin` (pass the registered `AppBlocker` Capacitor
|
|
42
|
+
* plugin) as a `NativeAppBlockerBackend`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createNativeAppBlockerBackend(plugin: AppBlockerPlugin): NativeAppBlockerBackend;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAEV,gBAAgB,EAEhB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAKvB,UAAU,uBAAuB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,MAAM,CAAC;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,EAAE,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,iCAAiC;IACzC,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;IACnE,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,MAAM,WAAW,uBAAuB;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,gBAAgB,IAAI,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAC/D,kBAAkB,IAAI,OAAO,CAAC,iCAAiC,CAAC,CAAC;IACjE,gBAAgB,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/D,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1C,SAAS,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC/C;AA0BD;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,gBAAgB,GACvB,uBAAuB,CAwBzB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
function toBackendStatus(status) {
|
|
2
|
+
return {
|
|
3
|
+
available: status.available,
|
|
4
|
+
active: status.active,
|
|
5
|
+
platform: status.platform,
|
|
6
|
+
engine: status.engine,
|
|
7
|
+
blockedCount: status.blockedCount,
|
|
8
|
+
blockedPackageNames: status.blockedPackageNames,
|
|
9
|
+
endsAt: status.endsAt,
|
|
10
|
+
permissionStatus: status.permissionStatus,
|
|
11
|
+
reason: status.reason,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function toBackendPermission(permission) {
|
|
15
|
+
return {
|
|
16
|
+
status: permission.status,
|
|
17
|
+
canRequest: permission.canRequest,
|
|
18
|
+
reason: permission.reason,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wrap an `AppBlockerPlugin` (pass the registered `AppBlocker` Capacitor
|
|
23
|
+
* plugin) as a `NativeAppBlockerBackend`.
|
|
24
|
+
*/
|
|
25
|
+
export function createNativeAppBlockerBackend(plugin) {
|
|
26
|
+
return {
|
|
27
|
+
async checkPermissions() {
|
|
28
|
+
return toBackendPermission(await plugin.checkPermissions());
|
|
29
|
+
},
|
|
30
|
+
async requestPermissions() {
|
|
31
|
+
return toBackendPermission(await plugin.requestPermissions());
|
|
32
|
+
},
|
|
33
|
+
getInstalledApps() {
|
|
34
|
+
return plugin.getInstalledApps();
|
|
35
|
+
},
|
|
36
|
+
selectApps() {
|
|
37
|
+
return plugin.selectApps();
|
|
38
|
+
},
|
|
39
|
+
blockApps(options) {
|
|
40
|
+
return plugin.blockApps(options);
|
|
41
|
+
},
|
|
42
|
+
unblockApps() {
|
|
43
|
+
return plugin.unblockApps();
|
|
44
|
+
},
|
|
45
|
+
async getStatus() {
|
|
46
|
+
return toBackendStatus(await plugin.getStatus());
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/backend.ts"],"names":[],"mappings":"AAwDA,SAAS,eAAe,CAAC,MAAwB;IAC/C,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,UAAsC;IAEtC,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,UAAU,EAAE,UAAU,CAAC,UAAU;QACjC,MAAM,EAAE,UAAU,CAAC,MAAM;KAC1B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAC3C,MAAwB;IAExB,OAAO;QACL,KAAK,CAAC,gBAAgB;YACpB,OAAO,mBAAmB,CAAC,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,KAAK,CAAC,kBAAkB;YACtB,OAAO,mBAAmB,CAAC,MAAM,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,gBAAgB;YACd,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACnC,CAAC;QACD,UAAU;YACR,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;QAC7B,CAAC;QACD,SAAS,CAAC,OAAO;YACf,OAAO,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC;QACD,WAAW;YACT,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC;QAC9B,CAAC;QACD,KAAK,CAAC,SAAS;YACb,OAAO,eAAe,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACnD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.test.d.ts","sourceRoot":"","sources":["../../src/backend.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createNativeAppBlockerBackend } from "./backend";
|
|
3
|
+
const CAPABILITIES = {
|
|
4
|
+
canSelectApps: true,
|
|
5
|
+
canBlockApps: true,
|
|
6
|
+
canScheduleTimedBlocks: false,
|
|
7
|
+
canUnblockEarly: true,
|
|
8
|
+
requiresFamilyControls: true,
|
|
9
|
+
requiresUsageAccess: false,
|
|
10
|
+
requiresOverlay: false,
|
|
11
|
+
};
|
|
12
|
+
function makeStatus(overrides = {}) {
|
|
13
|
+
return {
|
|
14
|
+
status: "inactive",
|
|
15
|
+
available: true,
|
|
16
|
+
active: false,
|
|
17
|
+
platform: "ios",
|
|
18
|
+
engine: "family-controls",
|
|
19
|
+
capabilities: CAPABILITIES,
|
|
20
|
+
blockedCount: 0,
|
|
21
|
+
blockedPackageNames: [],
|
|
22
|
+
endsAt: null,
|
|
23
|
+
permissionStatus: "granted",
|
|
24
|
+
canRequest: false,
|
|
25
|
+
canOpenSettings: true,
|
|
26
|
+
settingsTarget: "screenTime",
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function makePlugin(overrides = {}) {
|
|
31
|
+
return {
|
|
32
|
+
checkPermissions: vi.fn(async () => ({
|
|
33
|
+
status: "granted",
|
|
34
|
+
canRequest: false,
|
|
35
|
+
canOpenSettings: true,
|
|
36
|
+
settingsTarget: "screenTime",
|
|
37
|
+
engine: "family-controls",
|
|
38
|
+
capabilities: CAPABILITIES,
|
|
39
|
+
})),
|
|
40
|
+
requestPermissions: vi.fn(async () => ({
|
|
41
|
+
status: "granted",
|
|
42
|
+
canRequest: false,
|
|
43
|
+
canOpenSettings: true,
|
|
44
|
+
settingsTarget: "screenTime",
|
|
45
|
+
engine: "family-controls",
|
|
46
|
+
capabilities: CAPABILITIES,
|
|
47
|
+
})),
|
|
48
|
+
getInstalledApps: vi.fn(async () => ({ apps: [] })),
|
|
49
|
+
selectApps: vi.fn(async () => ({ apps: [], cancelled: false })),
|
|
50
|
+
blockApps: vi.fn(async () => ({
|
|
51
|
+
success: true,
|
|
52
|
+
endsAt: null,
|
|
53
|
+
blockedCount: 2,
|
|
54
|
+
})),
|
|
55
|
+
unblockApps: vi.fn(async () => ({ success: true })),
|
|
56
|
+
getStatus: vi.fn(async () => makeStatus()),
|
|
57
|
+
...overrides,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
describe("createNativeAppBlockerBackend", () => {
|
|
61
|
+
it("forwards blockApps to the Capacitor plugin", async () => {
|
|
62
|
+
const blockApps = vi.fn(async () => ({
|
|
63
|
+
success: true,
|
|
64
|
+
endsAt: null,
|
|
65
|
+
blockedCount: 3,
|
|
66
|
+
}));
|
|
67
|
+
const backend = createNativeAppBlockerBackend(makePlugin({ blockApps }));
|
|
68
|
+
const result = await backend.blockApps({ packageNames: ["a", "b", "c"] });
|
|
69
|
+
expect(blockApps).toHaveBeenCalledWith({ packageNames: ["a", "b", "c"] });
|
|
70
|
+
expect(result.blockedCount).toBe(3);
|
|
71
|
+
});
|
|
72
|
+
it("maps getStatus into the trimmed engine status shape", async () => {
|
|
73
|
+
const backend = createNativeAppBlockerBackend(makePlugin({
|
|
74
|
+
getStatus: vi.fn(async () => makeStatus({
|
|
75
|
+
active: true,
|
|
76
|
+
blockedCount: 2,
|
|
77
|
+
blockedPackageNames: ["com.x", "com.reddit"],
|
|
78
|
+
engine: "usage-stats-overlay",
|
|
79
|
+
platform: "android",
|
|
80
|
+
})),
|
|
81
|
+
}));
|
|
82
|
+
const status = await backend.getStatus();
|
|
83
|
+
expect(status).toEqual({
|
|
84
|
+
available: true,
|
|
85
|
+
active: true,
|
|
86
|
+
platform: "android",
|
|
87
|
+
engine: "usage-stats-overlay",
|
|
88
|
+
blockedCount: 2,
|
|
89
|
+
blockedPackageNames: ["com.x", "com.reddit"],
|
|
90
|
+
endsAt: null,
|
|
91
|
+
permissionStatus: "granted",
|
|
92
|
+
reason: undefined,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
it("maps permission checks into the trimmed engine permission shape", async () => {
|
|
96
|
+
const backend = createNativeAppBlockerBackend(makePlugin());
|
|
97
|
+
const permission = await backend.checkPermissions();
|
|
98
|
+
expect(permission).toEqual({
|
|
99
|
+
status: "granted",
|
|
100
|
+
canRequest: false,
|
|
101
|
+
reason: undefined,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it("forwards unblockApps to the Capacitor plugin", async () => {
|
|
105
|
+
const unblockApps = vi.fn(async () => ({ success: true }));
|
|
106
|
+
const backend = createNativeAppBlockerBackend(makePlugin({ unblockApps }));
|
|
107
|
+
const result = await backend.unblockApps();
|
|
108
|
+
expect(unblockApps).toHaveBeenCalledOnce();
|
|
109
|
+
expect(result.success).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=backend.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.test.js","sourceRoot":"","sources":["../../src/backend.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
export type AppBlockerPermissionStatus = "granted" | "denied" | "not-determined" | "not-applicable";
|
|
2
|
+
export type AppBlockerSettingsTarget = "screenTime" | "usageAccess" | "overlay" | "deviceSettings";
|
|
3
|
+
export interface AppBlockerCapabilities {
|
|
4
|
+
canSelectApps: boolean;
|
|
5
|
+
canBlockApps: boolean;
|
|
6
|
+
canScheduleTimedBlocks: boolean;
|
|
7
|
+
canUnblockEarly: boolean;
|
|
8
|
+
requiresFamilyControls: boolean;
|
|
9
|
+
requiresUsageAccess: boolean;
|
|
10
|
+
requiresOverlay: boolean;
|
|
11
|
+
}
|
|
2
12
|
export interface AppBlockerPermissionResult {
|
|
3
13
|
status: AppBlockerPermissionStatus;
|
|
4
14
|
canRequest: boolean;
|
|
15
|
+
canOpenSettings: boolean;
|
|
16
|
+
settingsTarget: AppBlockerSettingsTarget | null;
|
|
17
|
+
engine: AppBlockerStatus["engine"];
|
|
18
|
+
capabilities: AppBlockerCapabilities;
|
|
5
19
|
reason?: string;
|
|
6
20
|
}
|
|
7
21
|
export interface InstalledApp {
|
|
@@ -29,14 +43,19 @@ export interface UnblockAppsResult {
|
|
|
29
43
|
error?: string;
|
|
30
44
|
}
|
|
31
45
|
export interface AppBlockerStatus {
|
|
46
|
+
status: "active" | "inactive" | "unavailable";
|
|
32
47
|
available: boolean;
|
|
33
48
|
active: boolean;
|
|
34
49
|
platform: string;
|
|
35
50
|
engine: "family-controls" | "usage-stats-overlay" | "none";
|
|
51
|
+
capabilities: AppBlockerCapabilities;
|
|
36
52
|
blockedCount: number;
|
|
37
53
|
blockedPackageNames: string[];
|
|
38
54
|
endsAt: string | null;
|
|
39
55
|
permissionStatus: AppBlockerPermissionStatus;
|
|
56
|
+
canRequest: boolean;
|
|
57
|
+
canOpenSettings: boolean;
|
|
58
|
+
settingsTarget: AppBlockerSettingsTarget | null;
|
|
40
59
|
reason?: string;
|
|
41
60
|
}
|
|
42
61
|
export interface AppBlockerPlugin {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,QAAQ,GACR,gBAAgB,GAChB,gBAAgB,CAAC;AAErB,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,0BAA0B,CAAC;IACnC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,MAAM,CAAC;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,EAAE,0BAA0B,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACxD,kBAAkB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC1D,gBAAgB,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/D,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1C,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACxC"}
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,cAAc,eAAe,CAAC;AAK9B,eAAO,MAAM,UAAU,kBAErB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,cAAc,eAAe,CAAC;AAK9B,eAAO,MAAM,UAAU,kBAErB,CAAC;AAEH,OAAO,EACL,6BAA6B,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,WAAW,CAAC"}
|
package/dist/esm/index.js
CHANGED
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,cAAc,eAAe,CAAC;AAE9B,MAAM,OAAO,GAAG,GAAG,EAAE,CACnB,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;AAE/D,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAmB,iBAAiB,EAAE;IAC5E,GAAG,EAAE,OAAO;CACb,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,cAAc,eAAe,CAAC;AAE9B,MAAM,OAAO,GAAG,GAAG,EAAE,CACnB,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;AAE/D,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAmB,iBAAiB,EAAE;IAC5E,GAAG,EAAE,OAAO;CACb,CAAC,CAAC;AAEH,OAAO,EACL,6BAA6B,GAE9B,MAAM,WAAW,CAAC"}
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class AppBlockerWeb extends WebPlugin {
|
|
|
7
7
|
apps: [];
|
|
8
8
|
}>;
|
|
9
9
|
selectApps(): Promise<SelectAppsResult>;
|
|
10
|
-
blockApps(
|
|
10
|
+
blockApps(options: BlockAppsOptions): Promise<BlockAppsResult>;
|
|
11
11
|
unblockApps(): Promise<UnblockAppsResult>;
|
|
12
12
|
getStatus(): Promise<AppBlockerStatus>;
|
|
13
13
|
}
|
package/dist/esm/web.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAuCvB,qBAAa,aAAc,SAAQ,SAAS;IACpC,gBAAgB,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAoBvD,kBAAkB,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAoBzD,gBAAgB,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,EAAE,CAAA;KAAE,CAAC;IAIzC,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAIvC,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAU9D,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAOzC,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;CA0B7C"}
|
package/dist/esm/web.js
CHANGED
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
import { WebPlugin } from "@capacitor/core";
|
|
2
|
+
const PACKAGE_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/;
|
|
3
|
+
function validateBlockAppsOptions(options) {
|
|
4
|
+
const packageNames = Array.isArray(options?.packageNames)
|
|
5
|
+
? options.packageNames
|
|
6
|
+
: [];
|
|
7
|
+
const appTokens = Array.isArray(options?.appTokens) ? options.appTokens : [];
|
|
8
|
+
for (const packageName of packageNames) {
|
|
9
|
+
if (typeof packageName !== "string" ||
|
|
10
|
+
!PACKAGE_NAME_RE.test(packageName.trim())) {
|
|
11
|
+
throw new Error("packageNames must contain valid Android package names");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
for (const token of appTokens) {
|
|
15
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
16
|
+
throw new Error("appTokens must contain non-empty strings");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (options?.durationMinutes !== undefined &&
|
|
20
|
+
options.durationMinutes !== null) {
|
|
21
|
+
if (typeof options.durationMinutes !== "number" ||
|
|
22
|
+
!Number.isFinite(options.durationMinutes) ||
|
|
23
|
+
options.durationMinutes <= 0) {
|
|
24
|
+
throw new Error("durationMinutes must be a positive finite number");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
2
28
|
export class AppBlockerWeb extends WebPlugin {
|
|
3
29
|
async checkPermissions() {
|
|
4
30
|
return {
|
|
5
31
|
status: "not-applicable",
|
|
6
32
|
canRequest: false,
|
|
33
|
+
canOpenSettings: false,
|
|
34
|
+
settingsTarget: null,
|
|
35
|
+
engine: "none",
|
|
36
|
+
capabilities: {
|
|
37
|
+
canSelectApps: false,
|
|
38
|
+
canBlockApps: false,
|
|
39
|
+
canScheduleTimedBlocks: false,
|
|
40
|
+
canUnblockEarly: false,
|
|
41
|
+
requiresFamilyControls: false,
|
|
42
|
+
requiresUsageAccess: false,
|
|
43
|
+
requiresOverlay: false,
|
|
44
|
+
},
|
|
7
45
|
reason: "App blocking is only available on mobile devices.",
|
|
8
46
|
};
|
|
9
47
|
}
|
|
@@ -11,6 +49,18 @@ export class AppBlockerWeb extends WebPlugin {
|
|
|
11
49
|
return {
|
|
12
50
|
status: "not-applicable",
|
|
13
51
|
canRequest: false,
|
|
52
|
+
canOpenSettings: false,
|
|
53
|
+
settingsTarget: null,
|
|
54
|
+
engine: "none",
|
|
55
|
+
capabilities: {
|
|
56
|
+
canSelectApps: false,
|
|
57
|
+
canBlockApps: false,
|
|
58
|
+
canScheduleTimedBlocks: false,
|
|
59
|
+
canUnblockEarly: false,
|
|
60
|
+
requiresFamilyControls: false,
|
|
61
|
+
requiresUsageAccess: false,
|
|
62
|
+
requiresOverlay: false,
|
|
63
|
+
},
|
|
14
64
|
reason: "App blocking is only available on mobile devices.",
|
|
15
65
|
};
|
|
16
66
|
}
|
|
@@ -20,7 +70,8 @@ export class AppBlockerWeb extends WebPlugin {
|
|
|
20
70
|
async selectApps() {
|
|
21
71
|
return { apps: [], cancelled: true };
|
|
22
72
|
}
|
|
23
|
-
async blockApps(
|
|
73
|
+
async blockApps(options) {
|
|
74
|
+
validateBlockAppsOptions(options);
|
|
24
75
|
return {
|
|
25
76
|
success: false,
|
|
26
77
|
endsAt: null,
|
|
@@ -36,14 +87,27 @@ export class AppBlockerWeb extends WebPlugin {
|
|
|
36
87
|
}
|
|
37
88
|
async getStatus() {
|
|
38
89
|
return {
|
|
90
|
+
status: "unavailable",
|
|
39
91
|
available: false,
|
|
40
92
|
active: false,
|
|
41
93
|
platform: "web",
|
|
42
94
|
engine: "none",
|
|
95
|
+
capabilities: {
|
|
96
|
+
canSelectApps: false,
|
|
97
|
+
canBlockApps: false,
|
|
98
|
+
canScheduleTimedBlocks: false,
|
|
99
|
+
canUnblockEarly: false,
|
|
100
|
+
requiresFamilyControls: false,
|
|
101
|
+
requiresUsageAccess: false,
|
|
102
|
+
requiresOverlay: false,
|
|
103
|
+
},
|
|
43
104
|
blockedCount: 0,
|
|
44
105
|
blockedPackageNames: [],
|
|
45
106
|
endsAt: null,
|
|
46
107
|
permissionStatus: "not-applicable",
|
|
108
|
+
canRequest: false,
|
|
109
|
+
canOpenSettings: false,
|
|
110
|
+
settingsTarget: null,
|
|
47
111
|
reason: "App blocking is only available on mobile devices.",
|
|
48
112
|
};
|
|
49
113
|
}
|
package/dist/esm/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC1C,KAAK,CAAC,gBAAgB;QACpB,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,mDAAmD;SAC5D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,mDAAmD;SAC5D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.test.d.ts","sourceRoot":"","sources":["../../src/web.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { AppBlockerWeb } from "./web";
|
|
3
|
+
describe("AppBlockerWeb fallback", () => {
|
|
4
|
+
it("reports app blocking as unavailable on web", async () => {
|
|
5
|
+
const blocker = new AppBlockerWeb();
|
|
6
|
+
await expect(blocker.checkPermissions()).resolves.toMatchObject({
|
|
7
|
+
status: "not-applicable",
|
|
8
|
+
engine: "none",
|
|
9
|
+
canRequest: false,
|
|
10
|
+
});
|
|
11
|
+
await expect(blocker.getStatus()).resolves.toMatchObject({
|
|
12
|
+
status: "unavailable",
|
|
13
|
+
available: false,
|
|
14
|
+
active: false,
|
|
15
|
+
blockedCount: 0,
|
|
16
|
+
});
|
|
17
|
+
await expect(blocker.getInstalledApps()).resolves.toEqual({ apps: [] });
|
|
18
|
+
await expect(blocker.selectApps()).resolves.toEqual({
|
|
19
|
+
apps: [],
|
|
20
|
+
cancelled: true,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it.each([
|
|
24
|
+
{ packageNames: [""] },
|
|
25
|
+
{ packageNames: ["../settings"] },
|
|
26
|
+
{ packageNames: ["com..example"] },
|
|
27
|
+
{ packageNames: [{ name: "com.example.app" }] },
|
|
28
|
+
{ appTokens: ["valid", ""] },
|
|
29
|
+
{ appTokens: [42] },
|
|
30
|
+
{ durationMinutes: 0 },
|
|
31
|
+
{ durationMinutes: Number.POSITIVE_INFINITY },
|
|
32
|
+
{ durationMinutes: Number.NaN },
|
|
33
|
+
])("rejects malformed blockApps options %#", async (options) => {
|
|
34
|
+
await expect(new AppBlockerWeb().blockApps(options)).rejects.toThrow(/packageNames|appTokens|durationMinutes/);
|
|
35
|
+
});
|
|
36
|
+
it("returns a mobile-only block response for valid web fallback options", async () => {
|
|
37
|
+
await expect(new AppBlockerWeb().blockApps({
|
|
38
|
+
packageNames: ["com.example.app"],
|
|
39
|
+
appTokens: ["token-1"],
|
|
40
|
+
durationMinutes: 30,
|
|
41
|
+
})).resolves.toEqual({
|
|
42
|
+
success: false,
|
|
43
|
+
endsAt: null,
|
|
44
|
+
error: "App blocking is only available on mobile devices.",
|
|
45
|
+
blockedCount: 0,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=web.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.test.js","sourceRoot":"","sources":["../../src/web.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;QAEpC,MAAM,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC9D,MAAM,EAAE,gBAAgB;YACxB,MAAM,EAAE,MAAM;YACd,UAAU,EAAE,KAAK;SAClB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;YACvD,MAAM,EAAE,aAAa;YACrB,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,KAAK;YACb,YAAY,EAAE,CAAC;SAChB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACxE,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YAClD,IAAI,EAAE,EAAE;YACR,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE;QACtB,EAAE,YAAY,EAAE,CAAC,aAAa,CAAC,EAAE;QACjC,EAAE,YAAY,EAAE,CAAC,cAAc,CAAC,EAAE;QAClC,EAAE,YAAY,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAuB,CAAC,EAAE;QACpE,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE;QAC5B,EAAE,SAAS,EAAE,CAAC,EAAuB,CAAC,EAAE;QACxC,EAAE,eAAe,EAAE,CAAC,EAAE;QACtB,EAAE,eAAe,EAAE,MAAM,CAAC,iBAAiB,EAAE;QAC7C,EAAE,eAAe,EAAE,MAAM,CAAC,GAAG,EAAE;KAChC,CAAC,CAAC,wCAAwC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC7D,MAAM,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAClE,wCAAwC,CACzC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,CACV,IAAI,aAAa,EAAE,CAAC,SAAS,CAAC;YAC5B,YAAY,EAAE,CAAC,iBAAiB,CAAC;YACjC,SAAS,EAAE,CAAC,SAAS,CAAC;YACtB,eAAe,EAAE,EAAE;SACpB,CAAC,CACH,CAAC,QAAQ,CAAC,OAAO,CAAC;YACjB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,mDAAmD;YAC1D,YAAY,EAAE,CAAC;SAChB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -2,16 +2,104 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@capacitor/core');
|
|
4
4
|
|
|
5
|
+
function toBackendStatus(status) {
|
|
6
|
+
return {
|
|
7
|
+
available: status.available,
|
|
8
|
+
active: status.active,
|
|
9
|
+
platform: status.platform,
|
|
10
|
+
engine: status.engine,
|
|
11
|
+
blockedCount: status.blockedCount,
|
|
12
|
+
blockedPackageNames: status.blockedPackageNames,
|
|
13
|
+
endsAt: status.endsAt,
|
|
14
|
+
permissionStatus: status.permissionStatus,
|
|
15
|
+
reason: status.reason,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function toBackendPermission(permission) {
|
|
19
|
+
return {
|
|
20
|
+
status: permission.status,
|
|
21
|
+
canRequest: permission.canRequest,
|
|
22
|
+
reason: permission.reason,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Wrap an `AppBlockerPlugin` (pass the registered `AppBlocker` Capacitor
|
|
27
|
+
* plugin) as a `NativeAppBlockerBackend`.
|
|
28
|
+
*/
|
|
29
|
+
function createNativeAppBlockerBackend(plugin) {
|
|
30
|
+
return {
|
|
31
|
+
async checkPermissions() {
|
|
32
|
+
return toBackendPermission(await plugin.checkPermissions());
|
|
33
|
+
},
|
|
34
|
+
async requestPermissions() {
|
|
35
|
+
return toBackendPermission(await plugin.requestPermissions());
|
|
36
|
+
},
|
|
37
|
+
getInstalledApps() {
|
|
38
|
+
return plugin.getInstalledApps();
|
|
39
|
+
},
|
|
40
|
+
selectApps() {
|
|
41
|
+
return plugin.selectApps();
|
|
42
|
+
},
|
|
43
|
+
blockApps(options) {
|
|
44
|
+
return plugin.blockApps(options);
|
|
45
|
+
},
|
|
46
|
+
unblockApps() {
|
|
47
|
+
return plugin.unblockApps();
|
|
48
|
+
},
|
|
49
|
+
async getStatus() {
|
|
50
|
+
return toBackendStatus(await plugin.getStatus());
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
5
55
|
const loadWeb = () => Promise.resolve().then(function () { return web; }).then((module) => new module.AppBlockerWeb());
|
|
6
56
|
const AppBlocker = core.registerPlugin("ElizaAppBlocker", {
|
|
7
57
|
web: loadWeb,
|
|
8
58
|
});
|
|
9
59
|
|
|
60
|
+
const PACKAGE_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/;
|
|
61
|
+
function validateBlockAppsOptions(options) {
|
|
62
|
+
const packageNames = Array.isArray(options?.packageNames)
|
|
63
|
+
? options.packageNames
|
|
64
|
+
: [];
|
|
65
|
+
const appTokens = Array.isArray(options?.appTokens) ? options.appTokens : [];
|
|
66
|
+
for (const packageName of packageNames) {
|
|
67
|
+
if (typeof packageName !== "string" ||
|
|
68
|
+
!PACKAGE_NAME_RE.test(packageName.trim())) {
|
|
69
|
+
throw new Error("packageNames must contain valid Android package names");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const token of appTokens) {
|
|
73
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
74
|
+
throw new Error("appTokens must contain non-empty strings");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (options?.durationMinutes !== undefined &&
|
|
78
|
+
options.durationMinutes !== null) {
|
|
79
|
+
if (typeof options.durationMinutes !== "number" ||
|
|
80
|
+
!Number.isFinite(options.durationMinutes) ||
|
|
81
|
+
options.durationMinutes <= 0) {
|
|
82
|
+
throw new Error("durationMinutes must be a positive finite number");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
10
86
|
class AppBlockerWeb extends core.WebPlugin {
|
|
11
87
|
async checkPermissions() {
|
|
12
88
|
return {
|
|
13
89
|
status: "not-applicable",
|
|
14
90
|
canRequest: false,
|
|
91
|
+
canOpenSettings: false,
|
|
92
|
+
settingsTarget: null,
|
|
93
|
+
engine: "none",
|
|
94
|
+
capabilities: {
|
|
95
|
+
canSelectApps: false,
|
|
96
|
+
canBlockApps: false,
|
|
97
|
+
canScheduleTimedBlocks: false,
|
|
98
|
+
canUnblockEarly: false,
|
|
99
|
+
requiresFamilyControls: false,
|
|
100
|
+
requiresUsageAccess: false,
|
|
101
|
+
requiresOverlay: false,
|
|
102
|
+
},
|
|
15
103
|
reason: "App blocking is only available on mobile devices.",
|
|
16
104
|
};
|
|
17
105
|
}
|
|
@@ -19,6 +107,18 @@ class AppBlockerWeb extends core.WebPlugin {
|
|
|
19
107
|
return {
|
|
20
108
|
status: "not-applicable",
|
|
21
109
|
canRequest: false,
|
|
110
|
+
canOpenSettings: false,
|
|
111
|
+
settingsTarget: null,
|
|
112
|
+
engine: "none",
|
|
113
|
+
capabilities: {
|
|
114
|
+
canSelectApps: false,
|
|
115
|
+
canBlockApps: false,
|
|
116
|
+
canScheduleTimedBlocks: false,
|
|
117
|
+
canUnblockEarly: false,
|
|
118
|
+
requiresFamilyControls: false,
|
|
119
|
+
requiresUsageAccess: false,
|
|
120
|
+
requiresOverlay: false,
|
|
121
|
+
},
|
|
22
122
|
reason: "App blocking is only available on mobile devices.",
|
|
23
123
|
};
|
|
24
124
|
}
|
|
@@ -28,7 +128,8 @@ class AppBlockerWeb extends core.WebPlugin {
|
|
|
28
128
|
async selectApps() {
|
|
29
129
|
return { apps: [], cancelled: true };
|
|
30
130
|
}
|
|
31
|
-
async blockApps(
|
|
131
|
+
async blockApps(options) {
|
|
132
|
+
validateBlockAppsOptions(options);
|
|
32
133
|
return {
|
|
33
134
|
success: false,
|
|
34
135
|
endsAt: null,
|
|
@@ -44,14 +145,27 @@ class AppBlockerWeb extends core.WebPlugin {
|
|
|
44
145
|
}
|
|
45
146
|
async getStatus() {
|
|
46
147
|
return {
|
|
148
|
+
status: "unavailable",
|
|
47
149
|
available: false,
|
|
48
150
|
active: false,
|
|
49
151
|
platform: "web",
|
|
50
152
|
engine: "none",
|
|
153
|
+
capabilities: {
|
|
154
|
+
canSelectApps: false,
|
|
155
|
+
canBlockApps: false,
|
|
156
|
+
canScheduleTimedBlocks: false,
|
|
157
|
+
canUnblockEarly: false,
|
|
158
|
+
requiresFamilyControls: false,
|
|
159
|
+
requiresUsageAccess: false,
|
|
160
|
+
requiresOverlay: false,
|
|
161
|
+
},
|
|
51
162
|
blockedCount: 0,
|
|
52
163
|
blockedPackageNames: [],
|
|
53
164
|
endsAt: null,
|
|
54
165
|
permissionStatus: "not-applicable",
|
|
166
|
+
canRequest: false,
|
|
167
|
+
canOpenSettings: false,
|
|
168
|
+
settingsTarget: null,
|
|
55
169
|
reason: "App blocking is only available on mobile devices.",
|
|
56
170
|
};
|
|
57
171
|
}
|
|
@@ -63,4 +177,5 @@ var web = /*#__PURE__*/Object.freeze({
|
|
|
63
177
|
});
|
|
64
178
|
|
|
65
179
|
exports.AppBlocker = AppBlocker;
|
|
180
|
+
exports.createNativeAppBlockerBackend = createNativeAppBlockerBackend;
|
|
66
181
|
//# sourceMappingURL=plugin.cjs.js.map
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((module) => new module.AppBlockerWeb());\nexport const AppBlocker = registerPlugin(\"ElizaAppBlocker\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class AppBlockerWeb extends WebPlugin {\n async checkPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async requestPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async getInstalledApps() {\n return { apps: [] };\n }\n async selectApps() {\n return { apps: [], cancelled: true };\n }\n async blockApps(_options) {\n return {\n success: false,\n endsAt: null,\n error: \"App blocking is only available on mobile devices.\",\n blockedCount: 0,\n };\n }\n async unblockApps() {\n return {\n success: false,\n error: \"App blocking is only available on mobile devices.\",\n };\n }\n async getStatus() {\n return {\n available: false,\n active: false,\n platform: \"web\",\n engine: \"none\",\n blockedCount: 0,\n blockedPackageNames: [],\n endsAt: null,\n permissionStatus: \"not-applicable\",\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;AACtE,MAAC,UAAU,GAAGA,mBAAc,CAAC,iBAAiB,EAAE;AAC5D,IAAI,GAAG,EAAE,OAAO;AAChB,CAAC;;ACJM,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO;AACf,YAAY,MAAM,EAAE,gBAAgB;AACpC,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,MAAM,EAAE,mDAAmD;AACvE,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,OAAO;AACf,YAAY,MAAM,EAAE,gBAAgB;AACpC,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,MAAM,EAAE,mDAAmD;AACvE,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;AAC3B,IAAI;AACJ,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;AAC5C,IAAI;AACJ,IAAI,MAAM,SAAS,CAAC,QAAQ,EAAE;AAC9B,QAAQ,OAAO;AACf,YAAY,OAAO,EAAE,KAAK;AAC1B,YAAY,MAAM,EAAE,IAAI;AACxB,YAAY,KAAK,EAAE,mDAAmD;AACtE,YAAY,YAAY,EAAE,CAAC;AAC3B,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,OAAO;AACf,YAAY,OAAO,EAAE,KAAK;AAC1B,YAAY,KAAK,EAAE,mDAAmD;AACtE,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,OAAO;AACf,YAAY,SAAS,EAAE,KAAK;AAC5B,YAAY,MAAM,EAAE,KAAK;AACzB,YAAY,QAAQ,EAAE,KAAK;AAC3B,YAAY,MAAM,EAAE,MAAM;AAC1B,YAAY,YAAY,EAAE,CAAC;AAC3B,YAAY,mBAAmB,EAAE,EAAE;AACnC,YAAY,MAAM,EAAE,IAAI;AACxB,YAAY,gBAAgB,EAAE,gBAAgB;AAC9C,YAAY,MAAM,EAAE,mDAAmD;AACvE,SAAS;AACT,IAAI;AACJ;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/backend.js","esm/index.js","esm/web.js"],"sourcesContent":["function toBackendStatus(status) {\n return {\n available: status.available,\n active: status.active,\n platform: status.platform,\n engine: status.engine,\n blockedCount: status.blockedCount,\n blockedPackageNames: status.blockedPackageNames,\n endsAt: status.endsAt,\n permissionStatus: status.permissionStatus,\n reason: status.reason,\n };\n}\nfunction toBackendPermission(permission) {\n return {\n status: permission.status,\n canRequest: permission.canRequest,\n reason: permission.reason,\n };\n}\n/**\n * Wrap an `AppBlockerPlugin` (pass the registered `AppBlocker` Capacitor\n * plugin) as a `NativeAppBlockerBackend`.\n */\nexport function createNativeAppBlockerBackend(plugin) {\n return {\n async checkPermissions() {\n return toBackendPermission(await plugin.checkPermissions());\n },\n async requestPermissions() {\n return toBackendPermission(await plugin.requestPermissions());\n },\n getInstalledApps() {\n return plugin.getInstalledApps();\n },\n selectApps() {\n return plugin.selectApps();\n },\n blockApps(options) {\n return plugin.blockApps(options);\n },\n unblockApps() {\n return plugin.unblockApps();\n },\n async getStatus() {\n return toBackendStatus(await plugin.getStatus());\n },\n };\n}\n//# sourceMappingURL=backend.js.map","import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((module) => new module.AppBlockerWeb());\nexport const AppBlocker = registerPlugin(\"ElizaAppBlocker\", {\n web: loadWeb,\n});\nexport { createNativeAppBlockerBackend, } from \"./backend\";\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nconst PACKAGE_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*(?:\\.[A-Za-z][A-Za-z0-9_]*)+$/;\nfunction validateBlockAppsOptions(options) {\n const packageNames = Array.isArray(options?.packageNames)\n ? options.packageNames\n : [];\n const appTokens = Array.isArray(options?.appTokens) ? options.appTokens : [];\n for (const packageName of packageNames) {\n if (typeof packageName !== \"string\" ||\n !PACKAGE_NAME_RE.test(packageName.trim())) {\n throw new Error(\"packageNames must contain valid Android package names\");\n }\n }\n for (const token of appTokens) {\n if (typeof token !== \"string\" || token.trim().length === 0) {\n throw new Error(\"appTokens must contain non-empty strings\");\n }\n }\n if (options?.durationMinutes !== undefined &&\n options.durationMinutes !== null) {\n if (typeof options.durationMinutes !== \"number\" ||\n !Number.isFinite(options.durationMinutes) ||\n options.durationMinutes <= 0) {\n throw new Error(\"durationMinutes must be a positive finite number\");\n }\n }\n}\nexport class AppBlockerWeb extends WebPlugin {\n async checkPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n canOpenSettings: false,\n settingsTarget: null,\n engine: \"none\",\n capabilities: {\n canSelectApps: false,\n canBlockApps: false,\n canScheduleTimedBlocks: false,\n canUnblockEarly: false,\n requiresFamilyControls: false,\n requiresUsageAccess: false,\n requiresOverlay: false,\n },\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async requestPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n canOpenSettings: false,\n settingsTarget: null,\n engine: \"none\",\n capabilities: {\n canSelectApps: false,\n canBlockApps: false,\n canScheduleTimedBlocks: false,\n canUnblockEarly: false,\n requiresFamilyControls: false,\n requiresUsageAccess: false,\n requiresOverlay: false,\n },\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async getInstalledApps() {\n return { apps: [] };\n }\n async selectApps() {\n return { apps: [], cancelled: true };\n }\n async blockApps(options) {\n validateBlockAppsOptions(options);\n return {\n success: false,\n endsAt: null,\n error: \"App blocking is only available on mobile devices.\",\n blockedCount: 0,\n };\n }\n async unblockApps() {\n return {\n success: false,\n error: \"App blocking is only available on mobile devices.\",\n };\n }\n async getStatus() {\n return {\n status: \"unavailable\",\n available: false,\n active: false,\n platform: \"web\",\n engine: \"none\",\n capabilities: {\n canSelectApps: false,\n canBlockApps: false,\n canScheduleTimedBlocks: false,\n canUnblockEarly: false,\n requiresFamilyControls: false,\n requiresUsageAccess: false,\n requiresOverlay: false,\n },\n blockedCount: 0,\n blockedPackageNames: [],\n endsAt: null,\n permissionStatus: \"not-applicable\",\n canRequest: false,\n canOpenSettings: false,\n settingsTarget: null,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,16 +1,104 @@
|
|
|
1
1
|
var capacitorAppBlocker = (function (exports, core) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
function toBackendStatus(status) {
|
|
5
|
+
return {
|
|
6
|
+
available: status.available,
|
|
7
|
+
active: status.active,
|
|
8
|
+
platform: status.platform,
|
|
9
|
+
engine: status.engine,
|
|
10
|
+
blockedCount: status.blockedCount,
|
|
11
|
+
blockedPackageNames: status.blockedPackageNames,
|
|
12
|
+
endsAt: status.endsAt,
|
|
13
|
+
permissionStatus: status.permissionStatus,
|
|
14
|
+
reason: status.reason,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function toBackendPermission(permission) {
|
|
18
|
+
return {
|
|
19
|
+
status: permission.status,
|
|
20
|
+
canRequest: permission.canRequest,
|
|
21
|
+
reason: permission.reason,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Wrap an `AppBlockerPlugin` (pass the registered `AppBlocker` Capacitor
|
|
26
|
+
* plugin) as a `NativeAppBlockerBackend`.
|
|
27
|
+
*/
|
|
28
|
+
function createNativeAppBlockerBackend(plugin) {
|
|
29
|
+
return {
|
|
30
|
+
async checkPermissions() {
|
|
31
|
+
return toBackendPermission(await plugin.checkPermissions());
|
|
32
|
+
},
|
|
33
|
+
async requestPermissions() {
|
|
34
|
+
return toBackendPermission(await plugin.requestPermissions());
|
|
35
|
+
},
|
|
36
|
+
getInstalledApps() {
|
|
37
|
+
return plugin.getInstalledApps();
|
|
38
|
+
},
|
|
39
|
+
selectApps() {
|
|
40
|
+
return plugin.selectApps();
|
|
41
|
+
},
|
|
42
|
+
blockApps(options) {
|
|
43
|
+
return plugin.blockApps(options);
|
|
44
|
+
},
|
|
45
|
+
unblockApps() {
|
|
46
|
+
return plugin.unblockApps();
|
|
47
|
+
},
|
|
48
|
+
async getStatus() {
|
|
49
|
+
return toBackendStatus(await plugin.getStatus());
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
4
54
|
const loadWeb = () => Promise.resolve().then(function () { return web; }).then((module) => new module.AppBlockerWeb());
|
|
5
55
|
const AppBlocker = core.registerPlugin("ElizaAppBlocker", {
|
|
6
56
|
web: loadWeb,
|
|
7
57
|
});
|
|
8
58
|
|
|
59
|
+
const PACKAGE_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/;
|
|
60
|
+
function validateBlockAppsOptions(options) {
|
|
61
|
+
const packageNames = Array.isArray(options?.packageNames)
|
|
62
|
+
? options.packageNames
|
|
63
|
+
: [];
|
|
64
|
+
const appTokens = Array.isArray(options?.appTokens) ? options.appTokens : [];
|
|
65
|
+
for (const packageName of packageNames) {
|
|
66
|
+
if (typeof packageName !== "string" ||
|
|
67
|
+
!PACKAGE_NAME_RE.test(packageName.trim())) {
|
|
68
|
+
throw new Error("packageNames must contain valid Android package names");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const token of appTokens) {
|
|
72
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
73
|
+
throw new Error("appTokens must contain non-empty strings");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (options?.durationMinutes !== undefined &&
|
|
77
|
+
options.durationMinutes !== null) {
|
|
78
|
+
if (typeof options.durationMinutes !== "number" ||
|
|
79
|
+
!Number.isFinite(options.durationMinutes) ||
|
|
80
|
+
options.durationMinutes <= 0) {
|
|
81
|
+
throw new Error("durationMinutes must be a positive finite number");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
9
85
|
class AppBlockerWeb extends core.WebPlugin {
|
|
10
86
|
async checkPermissions() {
|
|
11
87
|
return {
|
|
12
88
|
status: "not-applicable",
|
|
13
89
|
canRequest: false,
|
|
90
|
+
canOpenSettings: false,
|
|
91
|
+
settingsTarget: null,
|
|
92
|
+
engine: "none",
|
|
93
|
+
capabilities: {
|
|
94
|
+
canSelectApps: false,
|
|
95
|
+
canBlockApps: false,
|
|
96
|
+
canScheduleTimedBlocks: false,
|
|
97
|
+
canUnblockEarly: false,
|
|
98
|
+
requiresFamilyControls: false,
|
|
99
|
+
requiresUsageAccess: false,
|
|
100
|
+
requiresOverlay: false,
|
|
101
|
+
},
|
|
14
102
|
reason: "App blocking is only available on mobile devices.",
|
|
15
103
|
};
|
|
16
104
|
}
|
|
@@ -18,6 +106,18 @@ var capacitorAppBlocker = (function (exports, core) {
|
|
|
18
106
|
return {
|
|
19
107
|
status: "not-applicable",
|
|
20
108
|
canRequest: false,
|
|
109
|
+
canOpenSettings: false,
|
|
110
|
+
settingsTarget: null,
|
|
111
|
+
engine: "none",
|
|
112
|
+
capabilities: {
|
|
113
|
+
canSelectApps: false,
|
|
114
|
+
canBlockApps: false,
|
|
115
|
+
canScheduleTimedBlocks: false,
|
|
116
|
+
canUnblockEarly: false,
|
|
117
|
+
requiresFamilyControls: false,
|
|
118
|
+
requiresUsageAccess: false,
|
|
119
|
+
requiresOverlay: false,
|
|
120
|
+
},
|
|
21
121
|
reason: "App blocking is only available on mobile devices.",
|
|
22
122
|
};
|
|
23
123
|
}
|
|
@@ -27,7 +127,8 @@ var capacitorAppBlocker = (function (exports, core) {
|
|
|
27
127
|
async selectApps() {
|
|
28
128
|
return { apps: [], cancelled: true };
|
|
29
129
|
}
|
|
30
|
-
async blockApps(
|
|
130
|
+
async blockApps(options) {
|
|
131
|
+
validateBlockAppsOptions(options);
|
|
31
132
|
return {
|
|
32
133
|
success: false,
|
|
33
134
|
endsAt: null,
|
|
@@ -43,14 +144,27 @@ var capacitorAppBlocker = (function (exports, core) {
|
|
|
43
144
|
}
|
|
44
145
|
async getStatus() {
|
|
45
146
|
return {
|
|
147
|
+
status: "unavailable",
|
|
46
148
|
available: false,
|
|
47
149
|
active: false,
|
|
48
150
|
platform: "web",
|
|
49
151
|
engine: "none",
|
|
152
|
+
capabilities: {
|
|
153
|
+
canSelectApps: false,
|
|
154
|
+
canBlockApps: false,
|
|
155
|
+
canScheduleTimedBlocks: false,
|
|
156
|
+
canUnblockEarly: false,
|
|
157
|
+
requiresFamilyControls: false,
|
|
158
|
+
requiresUsageAccess: false,
|
|
159
|
+
requiresOverlay: false,
|
|
160
|
+
},
|
|
50
161
|
blockedCount: 0,
|
|
51
162
|
blockedPackageNames: [],
|
|
52
163
|
endsAt: null,
|
|
53
164
|
permissionStatus: "not-applicable",
|
|
165
|
+
canRequest: false,
|
|
166
|
+
canOpenSettings: false,
|
|
167
|
+
settingsTarget: null,
|
|
54
168
|
reason: "App blocking is only available on mobile devices.",
|
|
55
169
|
};
|
|
56
170
|
}
|
|
@@ -62,6 +176,7 @@ var capacitorAppBlocker = (function (exports, core) {
|
|
|
62
176
|
});
|
|
63
177
|
|
|
64
178
|
exports.AppBlocker = AppBlocker;
|
|
179
|
+
exports.createNativeAppBlockerBackend = createNativeAppBlockerBackend;
|
|
65
180
|
|
|
66
181
|
return exports;
|
|
67
182
|
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((module) => new module.AppBlockerWeb());\nexport const AppBlocker = registerPlugin(\"ElizaAppBlocker\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class AppBlockerWeb extends WebPlugin {\n async checkPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async requestPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async getInstalledApps() {\n return { apps: [] };\n }\n async selectApps() {\n return { apps: [], cancelled: true };\n }\n async blockApps(_options) {\n return {\n success: false,\n endsAt: null,\n error: \"App blocking is only available on mobile devices.\",\n blockedCount: 0,\n };\n }\n async unblockApps() {\n return {\n success: false,\n error: \"App blocking is only available on mobile devices.\",\n };\n }\n async getStatus() {\n return {\n available: false,\n active: false,\n platform: \"web\",\n engine: \"none\",\n blockedCount: 0,\n blockedPackageNames: [],\n endsAt: null,\n permissionStatus: \"not-applicable\",\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;IAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;AACtE,UAAC,UAAU,GAAGA,mBAAc,CAAC,iBAAiB,EAAE;IAC5D,IAAI,GAAG,EAAE,OAAO;IAChB,CAAC;;ICJM,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO;IACf,YAAY,MAAM,EAAE,gBAAgB;IACpC,YAAY,UAAU,EAAE,KAAK;IAC7B,YAAY,MAAM,EAAE,mDAAmD;IACvE,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,OAAO;IACf,YAAY,MAAM,EAAE,gBAAgB;IACpC,YAAY,UAAU,EAAE,KAAK;IAC7B,YAAY,MAAM,EAAE,mDAAmD;IACvE,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;IAC3B,IAAI;IACJ,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;IAC5C,IAAI;IACJ,IAAI,MAAM,SAAS,CAAC,QAAQ,EAAE;IAC9B,QAAQ,OAAO;IACf,YAAY,OAAO,EAAE,KAAK;IAC1B,YAAY,MAAM,EAAE,IAAI;IACxB,YAAY,KAAK,EAAE,mDAAmD;IACtE,YAAY,YAAY,EAAE,CAAC;IAC3B,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,WAAW,GAAG;IACxB,QAAQ,OAAO;IACf,YAAY,OAAO,EAAE,KAAK;IAC1B,YAAY,KAAK,EAAE,mDAAmD;IACtE,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,SAAS,GAAG;IACtB,QAAQ,OAAO;IACf,YAAY,SAAS,EAAE,KAAK;IAC5B,YAAY,MAAM,EAAE,KAAK;IACzB,YAAY,QAAQ,EAAE,KAAK;IAC3B,YAAY,MAAM,EAAE,MAAM;IAC1B,YAAY,YAAY,EAAE,CAAC;IAC3B,YAAY,mBAAmB,EAAE,EAAE;IACnC,YAAY,MAAM,EAAE,IAAI;IACxB,YAAY,gBAAgB,EAAE,gBAAgB;IAC9C,YAAY,MAAM,EAAE,mDAAmD;IACvE,SAAS;IACT,IAAI;IACJ;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/backend.js","esm/index.js","esm/web.js"],"sourcesContent":["function toBackendStatus(status) {\n return {\n available: status.available,\n active: status.active,\n platform: status.platform,\n engine: status.engine,\n blockedCount: status.blockedCount,\n blockedPackageNames: status.blockedPackageNames,\n endsAt: status.endsAt,\n permissionStatus: status.permissionStatus,\n reason: status.reason,\n };\n}\nfunction toBackendPermission(permission) {\n return {\n status: permission.status,\n canRequest: permission.canRequest,\n reason: permission.reason,\n };\n}\n/**\n * Wrap an `AppBlockerPlugin` (pass the registered `AppBlocker` Capacitor\n * plugin) as a `NativeAppBlockerBackend`.\n */\nexport function createNativeAppBlockerBackend(plugin) {\n return {\n async checkPermissions() {\n return toBackendPermission(await plugin.checkPermissions());\n },\n async requestPermissions() {\n return toBackendPermission(await plugin.requestPermissions());\n },\n getInstalledApps() {\n return plugin.getInstalledApps();\n },\n selectApps() {\n return plugin.selectApps();\n },\n blockApps(options) {\n return plugin.blockApps(options);\n },\n unblockApps() {\n return plugin.unblockApps();\n },\n async getStatus() {\n return toBackendStatus(await plugin.getStatus());\n },\n };\n}\n//# sourceMappingURL=backend.js.map","import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((module) => new module.AppBlockerWeb());\nexport const AppBlocker = registerPlugin(\"ElizaAppBlocker\", {\n web: loadWeb,\n});\nexport { createNativeAppBlockerBackend, } from \"./backend\";\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nconst PACKAGE_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*(?:\\.[A-Za-z][A-Za-z0-9_]*)+$/;\nfunction validateBlockAppsOptions(options) {\n const packageNames = Array.isArray(options?.packageNames)\n ? options.packageNames\n : [];\n const appTokens = Array.isArray(options?.appTokens) ? options.appTokens : [];\n for (const packageName of packageNames) {\n if (typeof packageName !== \"string\" ||\n !PACKAGE_NAME_RE.test(packageName.trim())) {\n throw new Error(\"packageNames must contain valid Android package names\");\n }\n }\n for (const token of appTokens) {\n if (typeof token !== \"string\" || token.trim().length === 0) {\n throw new Error(\"appTokens must contain non-empty strings\");\n }\n }\n if (options?.durationMinutes !== undefined &&\n options.durationMinutes !== null) {\n if (typeof options.durationMinutes !== \"number\" ||\n !Number.isFinite(options.durationMinutes) ||\n options.durationMinutes <= 0) {\n throw new Error(\"durationMinutes must be a positive finite number\");\n }\n }\n}\nexport class AppBlockerWeb extends WebPlugin {\n async checkPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n canOpenSettings: false,\n settingsTarget: null,\n engine: \"none\",\n capabilities: {\n canSelectApps: false,\n canBlockApps: false,\n canScheduleTimedBlocks: false,\n canUnblockEarly: false,\n requiresFamilyControls: false,\n requiresUsageAccess: false,\n requiresOverlay: false,\n },\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async requestPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n canOpenSettings: false,\n settingsTarget: null,\n engine: \"none\",\n capabilities: {\n canSelectApps: false,\n canBlockApps: false,\n canScheduleTimedBlocks: false,\n canUnblockEarly: false,\n requiresFamilyControls: false,\n requiresUsageAccess: false,\n requiresOverlay: false,\n },\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async getInstalledApps() {\n return { apps: [] };\n }\n async selectApps() {\n return { apps: [], cancelled: true };\n }\n async blockApps(options) {\n validateBlockAppsOptions(options);\n return {\n success: false,\n endsAt: null,\n error: \"App blocking is only available on mobile devices.\",\n blockedCount: 0,\n };\n }\n async unblockApps() {\n return {\n success: false,\n error: \"App blocking is only available on mobile devices.\",\n };\n }\n async getStatus() {\n return {\n status: \"unavailable\",\n available: false,\n active: false,\n platform: \"web\",\n engine: \"none\",\n capabilities: {\n canSelectApps: false,\n canBlockApps: false,\n canScheduleTimedBlocks: false,\n canUnblockEarly: false,\n requiresFamilyControls: false,\n requiresUsageAccess: false,\n requiresOverlay: false,\n },\n blockedCount: 0,\n blockedPackageNames: [],\n endsAt: null,\n permissionStatus: \"not-applicable\",\n canRequest: false,\n canOpenSettings: false,\n settingsTarget: null,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
|
|
@@ -97,7 +97,7 @@ public class ElizaAppBlockerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
97
97
|
call.resolve([
|
|
98
98
|
"success": false,
|
|
99
99
|
"endsAt": NSNull(),
|
|
100
|
-
"error": "Timed iPhone app blocking
|
|
100
|
+
"error": "Timed iPhone app blocking requires a DeviceActivity extension. Omit durationMinutes for an indefinite block, then call unblockApps when the block should end.",
|
|
101
101
|
"blockedCount": 0,
|
|
102
102
|
])
|
|
103
103
|
return
|
|
@@ -136,16 +136,22 @@ public class ElizaAppBlockerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
136
136
|
let permissionStatus = permission["status"] as? String ?? "not-determined"
|
|
137
137
|
let reason = permission["reason"] as? String
|
|
138
138
|
let blockedCount = state?.tokenDataArray.count ?? 0
|
|
139
|
+
let active = permissionStatus == "granted" && blockedCount > 0
|
|
139
140
|
|
|
140
141
|
call.resolve([
|
|
142
|
+
"status": active ? "active" : "inactive",
|
|
141
143
|
"available": true,
|
|
142
|
-
"active":
|
|
144
|
+
"active": active,
|
|
143
145
|
"platform": "ios",
|
|
144
146
|
"engine": "family-controls",
|
|
147
|
+
"capabilities": appBlockerCapabilities(),
|
|
145
148
|
"blockedCount": blockedCount,
|
|
146
149
|
"blockedPackageNames": [],
|
|
147
150
|
"endsAt": nullable(AppBlockerShared.endsAtString(for: state)),
|
|
148
151
|
"permissionStatus": permissionStatus,
|
|
152
|
+
"canRequest": permission["canRequest"] as? Bool ?? false,
|
|
153
|
+
"canOpenSettings": permission["canOpenSettings"] as? Bool ?? true,
|
|
154
|
+
"settingsTarget": nullable(permission["settingsTarget"]),
|
|
149
155
|
"reason": nullable(reason),
|
|
150
156
|
])
|
|
151
157
|
}
|
|
@@ -154,22 +160,30 @@ public class ElizaAppBlockerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
154
160
|
let status = AuthorizationCenter.shared.authorizationStatus
|
|
155
161
|
let mappedStatus: String
|
|
156
162
|
let canRequest: Bool
|
|
163
|
+
let settingsTarget: Any
|
|
157
164
|
|
|
158
165
|
switch status {
|
|
159
166
|
case .approved:
|
|
160
167
|
mappedStatus = "granted"
|
|
161
168
|
canRequest = false
|
|
169
|
+
settingsTarget = NSNull()
|
|
162
170
|
case .notDetermined:
|
|
163
171
|
mappedStatus = "not-determined"
|
|
164
172
|
canRequest = true
|
|
173
|
+
settingsTarget = "screenTime"
|
|
165
174
|
default:
|
|
166
175
|
mappedStatus = "denied"
|
|
167
176
|
canRequest = true
|
|
177
|
+
settingsTarget = "screenTime"
|
|
168
178
|
}
|
|
169
179
|
|
|
170
180
|
var result: [String: Any] = [
|
|
171
181
|
"status": mappedStatus,
|
|
172
182
|
"canRequest": canRequest,
|
|
183
|
+
"canOpenSettings": mappedStatus != "granted",
|
|
184
|
+
"settingsTarget": settingsTarget,
|
|
185
|
+
"engine": "family-controls",
|
|
186
|
+
"capabilities": appBlockerCapabilities(),
|
|
173
187
|
]
|
|
174
188
|
|
|
175
189
|
if let reason = reasonOverride ?? permissionReason(for: status) {
|
|
@@ -179,6 +193,18 @@ public class ElizaAppBlockerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
179
193
|
return result
|
|
180
194
|
}
|
|
181
195
|
|
|
196
|
+
private func appBlockerCapabilities() -> [String: Any] {
|
|
197
|
+
[
|
|
198
|
+
"canSelectApps": true,
|
|
199
|
+
"canBlockApps": true,
|
|
200
|
+
"canScheduleTimedBlocks": false,
|
|
201
|
+
"canUnblockEarly": true,
|
|
202
|
+
"requiresFamilyControls": true,
|
|
203
|
+
"requiresUsageAccess": false,
|
|
204
|
+
"requiresOverlay": false,
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
|
|
182
208
|
private func permissionReason(for status: AuthorizationStatus) -> String? {
|
|
183
209
|
switch status {
|
|
184
210
|
case .approved:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/capacitor-appblocker",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3-beta.3",
|
|
4
4
|
"description": "Blocks selected apps on Android with Usage Access and an overlay shield, and on iPhone with Family Controls.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app-blocker",
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/esm/index.d.ts",
|
|
17
|
+
"bun": "./src/index.ts",
|
|
18
|
+
"development": "./src/index.ts",
|
|
17
19
|
"import": "./dist/esm/index.js",
|
|
18
20
|
"require": "./dist/plugin.cjs.js"
|
|
19
21
|
},
|
|
@@ -29,16 +31,18 @@
|
|
|
29
31
|
"dist"
|
|
30
32
|
],
|
|
31
33
|
"scripts": {
|
|
32
|
-
"build": "
|
|
33
|
-
"clean": "node
|
|
34
|
-
"
|
|
34
|
+
"build": "node ../../packages/scripts/with-package-build-lock.mjs plugins/plugin-native-appblocker -- bun run build:unlocked",
|
|
35
|
+
"clean": "node ../../packages/scripts/rm-path-recursive.mjs dist",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"prepublishOnly": "bun run build",
|
|
38
|
+
"build:unlocked": "bun run clean && tsc && bunx rollup -c rollup.config.mjs"
|
|
35
39
|
},
|
|
36
40
|
"author": "elizaOS",
|
|
37
41
|
"license": "MIT",
|
|
38
42
|
"repository": {
|
|
39
43
|
"type": "git",
|
|
40
44
|
"url": "https://github.com/elizaOS/eliza.git",
|
|
41
|
-
"directory": "
|
|
45
|
+
"directory": "plugins/plugin-native-appblocker"
|
|
42
46
|
},
|
|
43
47
|
"capacitor": {
|
|
44
48
|
"ios": {
|
|
@@ -50,11 +54,10 @@
|
|
|
50
54
|
}
|
|
51
55
|
},
|
|
52
56
|
"devDependencies": {
|
|
53
|
-
"@capacitor/cli": "^8.0.0",
|
|
54
57
|
"@capacitor/core": "^8.3.1",
|
|
55
|
-
"rimraf": "^6.0.0",
|
|
56
58
|
"rollup": "^4.60.2",
|
|
57
|
-
"typescript": "^6.0.3"
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"vitest": "^4.0.0"
|
|
58
61
|
},
|
|
59
62
|
"peerDependencies": {
|
|
60
63
|
"@capacitor/core": "^8.3.1"
|
|
@@ -74,5 +77,6 @@
|
|
|
74
77
|
"ios": "Uses Family Controls and Managed Settings to shield selected apps.",
|
|
75
78
|
"android": "Uses Usage Access polling plus a system overlay shield."
|
|
76
79
|
}
|
|
77
|
-
}
|
|
80
|
+
},
|
|
81
|
+
"gitHead": "f54b0f4eaed317d59fa7dbcdce20f4cdb0734420"
|
|
78
82
|
}
|