@burdenoff/fe-libs 2026.1013.1 → 2026.1013.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.
@@ -45,8 +45,8 @@ function j(j) {
45
45
  ...p(j.appName),
46
46
  ...j.backButton
47
47
  })), O("deepLinks", () => _()), O("network", () => b(j.network ?? {})), O("runtimeHooks", () => u(j.runtimeHooks ?? {})), j.push?.enabled && j.plugins?.pushNotifications) {
48
- let e = j.plugins.pushNotifications;
49
- O("push", () => S(e, j.push ?? {}));
48
+ let e = j.plugins.pushNotifications, t = j.plugins.localNotifications;
49
+ O("push", () => S(e, j.push ?? {}, t));
50
50
  }
51
51
  return l() && j.splash?.autoHide !== !1 && O("splashSafetyTimer", () => T(j.splash?.maxWaitMs ?? 8e3)), O("pwa", () => w({
52
52
  enabled: !0,
@@ -16,6 +16,8 @@
16
16
  * plugins: {
17
17
  * updater: () => import('@capgo/capacitor-updater'),
18
18
  * pushNotifications: () => import('@capacitor-firebase/messaging'),
19
+ * // Android foreground push display only — see LocalNotificationsLike.
20
+ * localNotifications: () => import('@capacitor/local-notifications'),
19
21
  * },
20
22
  * push: { enabled: true },
21
23
  * });
@@ -51,5 +53,5 @@ export { configureElectronGlobalKey, getDesktopBridge, getElectronGlobalKey, get
51
53
  export { defineCapacitorConfig, isValidAllowNavigationRule, type CapacitorConfigLike, } from './capacitor-config';
52
54
  export { defineWebManifest, type WebManifestIcon, type WebManifestLike, type WebManifestPushConfig, type WebManifestShortcut, } from './web-manifest';
53
55
  export { renderServiceWorker, SERVICE_WORKER_TEMPLATE } from './service-worker';
54
- export type { AuthInterceptOptions, BackButtonHandlers, BeforeInstallPromptEventLike, BootNativeShellOptions, CapacitorListenerHandleLike, CapacitorUpdaterLike, DeepLinkDetail, LegacyElectronBridge, MobileRuntimeHooks, NativeConfig, NativePreviewMode, NativeShellHandle, NativeShellPlatform, NetworkHooks, NetworkStatusDetail, OptionalPluginLoaders, PushActionPerformedLike, PushNotificationSchemaLike, PushNotificationsLike, PushNotificationsLoader, PushOptions, PushPermissionStateLike, PushTokenLike, PwaOptions, SplashOptions, UpdaterLoader, } from './types';
56
+ export type { AuthInterceptOptions, BackButtonHandlers, BeforeInstallPromptEventLike, BootNativeShellOptions, CapacitorListenerHandleLike, CapacitorUpdaterLike, DeepLinkDetail, LegacyElectronBridge, MobileRuntimeHooks, NativeConfig, LocalNotificationsLike, LocalNotificationsLoader, NativePreviewMode, NativeShellHandle, NativeShellPlatform, NetworkHooks, NetworkStatusDetail, OptionalPluginLoaders, PushActionPerformedLike, PushNotificationSchemaLike, PushNotificationsLike, PushNotificationsLoader, PushOptions, PushPermissionStateLike, PushTokenLike, PwaOptions, SplashOptions, UpdaterLoader, } from './types';
55
57
  export { installPushOptIn, resetPushOptInForTests } from './push-optin';
@@ -1,5 +1,5 @@
1
1
  import { PushTokenEventDetail } from '../shared/native/types';
2
- import { PushNotificationsLoader, PushOptions, PushPermissionStateLike } from './types';
2
+ import { LocalNotificationsLoader, PushNotificationsLoader, PushOptions, PushPermissionStateLike } from './types';
3
3
  export declare const PUSH_TOKEN_EVENT = "burdenoff:pushToken";
4
4
  /**
5
5
  * Publish a push token to the rest of the app: `window.__burdenoffPushToken`
@@ -15,7 +15,7 @@ export declare function emitPushToken(value: string, platform: PushTokenEventDet
15
15
  * `window.__burdenoffPushToken`; notification tap → deep-link navigator).
16
16
  * Does NOT prompt for permission — call `requestPushPermission()` for that.
17
17
  */
18
- export declare function installPushNotifications(loader: PushNotificationsLoader, options?: Pick<PushOptions, 'onToken' | 'onNotificationAction' | 'onNotificationReceived'>): Promise<void>;
18
+ export declare function installPushNotifications(loader: PushNotificationsLoader, options?: Pick<PushOptions, 'onToken' | 'onNotificationAction' | 'onNotificationReceived'>, localNotificationsLoader?: LocalNotificationsLoader): Promise<void>;
19
19
  /**
20
20
  * Read current native permission state WITHOUT prompting.
21
21
  *
@@ -22,7 +22,34 @@ async function s() {
22
22
  }
23
23
  return a;
24
24
  }
25
- function c(e) {
25
+ var c = null, l = null;
26
+ async function u(e) {
27
+ if (!e || !t()) return null;
28
+ if (l !== e && (c = null, l = e), c) return c;
29
+ try {
30
+ let t = (await e()).LocalNotifications ?? null;
31
+ c = t ? { plugin: t } : null;
32
+ } catch {
33
+ c = null;
34
+ }
35
+ return c;
36
+ }
37
+ var d = 0;
38
+ async function f(e, t) {
39
+ try {
40
+ let n = await u(e);
41
+ if (!n || (await n.plugin.checkPermissions()).display !== "granted") return;
42
+ await n.plugin.schedule({ notifications: [{
43
+ id: ++d % 2147483647,
44
+ title: t.title ?? "",
45
+ body: t.body ?? "",
46
+ channelId: "default",
47
+ extra: t.data ?? void 0,
48
+ isExactNotification: !1
49
+ }] });
50
+ } catch {}
51
+ }
52
+ function p(e) {
26
53
  let t = e.notification.data;
27
54
  if (!t || typeof t != "object") return null;
28
55
  let n = t.route;
@@ -36,7 +63,7 @@ function c(e) {
36
63
  }
37
64
  return null;
38
65
  }
39
- async function l(t, r = {}) {
66
+ async function m(t, r = {}, c) {
40
67
  o !== t && (a = null, o = t);
41
68
  let l = await s();
42
69
  if (!l) return;
@@ -47,9 +74,9 @@ async function l(t, r = {}) {
47
74
  i(t.token, d), r.onToken?.(t.token, d);
48
75
  }), await u.addListener("notificationReceived", (e) => {
49
76
  let t = e;
50
- r.onNotificationReceived?.(t.notification);
77
+ d === "android" && f(c, t.notification), r.onNotificationReceived?.(t.notification);
51
78
  }), await u.addListener("notificationActionPerformed", (e) => {
52
- let t = e, i = c(t);
79
+ let t = e, i = p(t);
53
80
  i && n(i), r.onNotificationAction?.(t);
54
81
  }), d === "android" && await u.createChannel({
55
82
  id: "default",
@@ -61,7 +88,7 @@ async function l(t, r = {}) {
61
88
  }
62
89
  } catch {}
63
90
  }
64
- async function u() {
91
+ async function h() {
65
92
  try {
66
93
  let e = await s();
67
94
  return e ? (await e.plugin.checkPermissions()).receive : null;
@@ -69,7 +96,7 @@ async function u() {
69
96
  return null;
70
97
  }
71
98
  }
72
- async function d() {
99
+ async function g() {
73
100
  try {
74
101
  let t = await s();
75
102
  if (!t) return !1;
@@ -82,4 +109,4 @@ async function d() {
82
109
  }
83
110
  }
84
111
  //#endregion
85
- export { r as PUSH_TOKEN_EVENT, u as checkPushPermission, i as emitPushToken, l as installPushNotifications, d as requestPushPermission };
112
+ export { r as PUSH_TOKEN_EVENT, h as checkPushPermission, i as emitPushToken, m as installPushNotifications, g as requestPushPermission };
@@ -201,17 +201,65 @@ export interface PushNotificationsLike {
201
201
  }): Promise<void>;
202
202
  addListener(eventName: 'tokenReceived' | 'notificationReceived' | 'notificationActionPerformed', listener: (payload: unknown) => void): Promise<CapacitorListenerHandleLike>;
203
203
  }
204
+ /**
205
+ * Structural subset of `@capacitor/local-notifications`' `LocalNotifications`.
206
+ *
207
+ * Only used for ANDROID foreground push display. `notificationReceived`
208
+ * (`PushOptions.onNotificationReceived`) fires ONLY while the app is in the
209
+ * foreground — Android's OS auto-displays a backgrounded/killed app's
210
+ * notification-type message via the system tray directly, bypassing JS
211
+ * entirely, so this listener is never reached for that case. In the
212
+ * foreground, neither platform auto-displays anything: iOS's own
213
+ * `presentationOptions` config handles that side: Android has no such
214
+ * mechanism, and without this, a push received while the app is open is
215
+ * silently never shown — confirmed live: FCM reported successful delivery,
216
+ * nothing appeared, because the app was foregrounded and nothing built a
217
+ * system notification in response.
218
+ */
219
+ export interface LocalNotificationsLike {
220
+ checkPermissions(): Promise<{
221
+ display: PushPermissionStateLike;
222
+ }>;
223
+ schedule(options: {
224
+ notifications: Array<{
225
+ id: number;
226
+ title: string;
227
+ body: string;
228
+ channelId?: string;
229
+ extra?: Record<string, unknown>;
230
+ /**
231
+ * Defaults to `true` in the plugin itself, and is checked at the
232
+ * `schedule()` call level regardless of whether a `schedule`
233
+ * (at/every/on) is even set — leaving it unset pops Android 12+'s
234
+ * "Alarms & reminders" settings screen before posting anything, even
235
+ * for an immediate, non-alarm notification. Always pass `false` here
236
+ * unless a future caller genuinely needs AlarmManager-backed exact
237
+ * scheduling.
238
+ */
239
+ isExactNotification?: boolean;
240
+ }>;
241
+ }): Promise<unknown>;
242
+ }
204
243
  export type UpdaterLoader = () => Promise<{
205
244
  CapacitorUpdater: CapacitorUpdaterLike;
206
245
  }>;
207
246
  export type PushNotificationsLoader = () => Promise<{
208
247
  FirebaseMessaging: PushNotificationsLike;
209
248
  }>;
249
+ export type LocalNotificationsLoader = () => Promise<{
250
+ LocalNotifications: LocalNotificationsLike;
251
+ }>;
210
252
  export interface OptionalPluginLoaders {
211
253
  /** `() => import('@capgo/capacitor-updater')` */
212
254
  updater?: UpdaterLoader;
213
255
  /** `() => import('@capacitor-firebase/messaging')` */
214
256
  pushNotifications?: PushNotificationsLoader;
257
+ /**
258
+ * `() => import('@capacitor/local-notifications')` — Android foreground
259
+ * push display only. Optional: a shell that never enables push, or
260
+ * accepts silent foreground pushes, can omit this entirely.
261
+ */
262
+ localNotifications?: LocalNotificationsLoader;
215
263
  }
216
264
  export interface PushOptions {
217
265
  enabled: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/fe-libs",
3
- "version": "2026.1013.1",
3
+ "version": "2026.1013.3",
4
4
  "description": "Burdenoff frontend primitives and domain libraries",
5
5
  "type": "module",
6
6
  "bin": {