SkateSpots/packages/skatespots-background/src/index.ts
SkateSpots 3ad214683a feat(android): native background poller plugin (no Google) - Cordn pattern
packages/skatespots-background: a local Capacitor Android plugin that polls our
own push-service /pending and raises local notifications. Modes: off / standard
(WorkManager ~15 min) / fast (foreground service ~5 min). Kotlin +
AndroidManifest (POST_NOTIFICATIONS, FOREGROUND_SERVICE_DATA_SYNC, WAKE_LOCK,
battery-exemption) + Gradle module. Client: useBackgroundDelivery (registers a
poll token via NIP-98, seeds the plugin) + a Background delivery (Android)
control in NotificationSettingsCard. The app registers by NAME, not by importing
the package, so the web bundle is unaffected. UNVERIFIED - needs cap sync + a
device.
2026-10-01 19:51:56 +07:00

55 lines
2.2 KiB
TypeScript

/**
* SkateSpots background delivery — TS↔Kotlin bridge.
*
* A native poller that asks our OWN `push-service` "anything new since N?" and
* raises a **local notification** when it moves — the Cordn pattern, with **no
* Google**. `/pending` returns only a content-free cursor, so the worker never
* decrypts anything.
*
* Every method rejects on web; callers guard with `isNativePlatform()`.
*/
import { registerPlugin } from '@capacitor/core';
/** `off` | `standard` (WorkManager ~15 min) | `fast` (foreground service ~5 min). */
export type DeliveryMode = 'off' | 'standard' | 'fast';
export interface ConfigureOptions {
mode: DeliveryMode;
/** Minutes between foreground-service polls. Only used by `fast`. Default 5. */
intervalMinutes?: number;
}
export interface SeedOptions {
/** Base URL of the push service, e.g. https://push.skate-spots.org */
baseUrl: string;
/** The poll token from `/native/poll/register`. */
token: string;
/** The cursor we already know — the worker only notifies when it advances. */
since: number;
}
export interface PostNotificationOptions {
title?: string;
body?: string;
/** In-app path to open on tap (HashRouter), e.g. /#/trades */
url?: string;
}
export interface SkateSpotsBackgroundPlugin {
/** Set the delivery mode; starts/stops the foreground service accordingly. */
configure(options: ConfigureOptions): Promise<void>;
/** Store the poll target (base URL + token + cursor). Call on enable/login. */
seed(options: SeedOptions): Promise<void>;
/** Post a local notification (used by the live in-app path for consistency). */
postNotification(options?: PostNotificationOptions): Promise<void>;
/** Cancel all message notifications. */
clearNotifications(): Promise<void>;
/** A tapped notification's in-app path (HashRouter), consumed once. */
consumePendingUrl(): Promise<{ url: string | null }>;
/** Whether the app is exempt from Doze/battery optimization. */
isBatteryExempted(): Promise<{ exempted: boolean }>;
/** Open the system "disable battery optimization" prompt. */
requestBatteryExemption(): Promise<void>;
}
export const SkateSpotsBackground = registerPlugin<SkateSpotsBackgroundPlugin>('SkateSpotsBackground');