@pmate/bridge 0.1.5 → 0.1.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/bridge",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "files": [
5
5
  "src",
6
6
  "global.d.ts"
@@ -15,11 +15,11 @@
15
15
  }
16
16
  },
17
17
  "devDependencies": {
18
- "@types/react": "catalog:",
19
- "react": "catalog:"
18
+ "@types/react": "^19.2.7",
19
+ "react": "^19.1.1"
20
20
  },
21
21
  "main": "src/index.ts",
22
22
  "exports": {
23
23
  ".": "./src/index.ts"
24
24
  }
25
- }
25
+ }
@@ -2,6 +2,8 @@ import { PropsWithChildren, ReactNode, useEffect, useMemo, useState } from "reac
2
2
  import { PmateBridgeContext } from "./context"
3
3
  import {
4
4
  getFallbackSafeInsets,
5
+ getNotificationStatus,
6
+ getPushToken,
5
7
  pickFileBridge,
6
8
  readDeviceInfo,
7
9
  readIsPmate,
@@ -84,6 +86,8 @@ export function PmateBridgeProvider({
84
86
  safeInsetsState,
85
87
  deviceInfoState,
86
88
  requestPermissions: requestPermissionsBridge,
89
+ getNotificationStatus,
90
+ getPushToken,
87
91
  pickFile: pickFileBridge,
88
92
  }),
89
93
  [deviceInfoState, isPmate, safeInsetsState]
package/src/context.tsx CHANGED
@@ -1,8 +1,11 @@
1
1
  import { createContext, useContext } from "react"
2
2
  import type {
3
3
  DeviceInfoState,
4
+ NotificationStatus,
4
5
  PermissionResult,
5
6
  PickedFile,
7
+ PushTokenInfo,
8
+ PushTokenOptions,
6
9
  SafeInsetsState,
7
10
  } from "./types"
8
11
 
@@ -11,6 +14,8 @@ export interface PmateBridgeContextValue {
11
14
  safeInsetsState: SafeInsetsState
12
15
  deviceInfoState: DeviceInfoState
13
16
  requestPermissions: (permissions: string[]) => Promise<PermissionResult>
17
+ getNotificationStatus: () => Promise<NotificationStatus>
18
+ getPushToken: (options?: PushTokenOptions) => Promise<PushTokenInfo | undefined>
14
19
  pickFile: () => Promise<PickedFile[]>
15
20
  }
16
21
 
package/src/hooks.ts CHANGED
@@ -2,13 +2,15 @@ import { useCallback, useEffect, useState } from "react"
2
2
  import { useOptionalPmateBridgeContext } from "./context"
3
3
  import {
4
4
  getFallbackSafeInsets,
5
+ getNotificationStatus,
6
+ getPushToken,
5
7
  pickFileBridge,
6
8
  readDeviceInfo,
7
9
  readIsPmate,
8
10
  readSafeInsets,
9
11
  requestPermissionsBridge,
10
12
  } from "./internal"
11
- import type { DeviceInfoState, SafeInsetsState } from "./types"
13
+ import type { DeviceInfoState, PushTokenOptions, SafeInsetsState } from "./types"
12
14
 
13
15
  export function useIsPmate() {
14
16
  return useOptionalPmateBridgeContext()?.isPmate ?? readIsPmate()
@@ -93,3 +95,19 @@ export function useRequestPermissions() {
93
95
  [context]
94
96
  )
95
97
  }
98
+
99
+ export function useNotificationStatus() {
100
+ const context = useOptionalPmateBridgeContext()
101
+ return useCallback(
102
+ () => context?.getNotificationStatus() ?? getNotificationStatus(),
103
+ [context]
104
+ )
105
+ }
106
+
107
+ export function useGetPushToken() {
108
+ const context = useOptionalPmateBridgeContext()
109
+ return useCallback(
110
+ (options?: PushTokenOptions) => context?.getPushToken(options) ?? getPushToken(options),
111
+ [context]
112
+ )
113
+ }
package/src/index.ts CHANGED
@@ -2,15 +2,24 @@ export * from "./PmateBridgeProvider"
2
2
  export * from "./SafeAreaVarsProvider"
3
3
  export * from "./hooks"
4
4
  export {
5
+ cancelAlarm,
6
+ cancelAllAlarms,
5
7
  connectBluetoothDevice,
6
8
  disconnectBluetoothDevice,
9
+ getAlarm,
10
+ getAlarmCapabilities,
7
11
  getBluetoothCapabilities,
8
12
  getConnectedBluetoothDevices,
9
13
  getNotificationStatus,
10
14
  getPushToken,
15
+ isAndroidDevice,
16
+ isIOSDevice,
17
+ listAlarms,
18
+ onAlarmEvent,
11
19
  onBluetoothEvent,
12
20
  readBluetooth,
13
21
  requestBluetoothPermission,
22
+ scheduleAlarm,
14
23
  scanBluetoothDevices,
15
24
  stopBluetoothScan,
16
25
  subscribeBluetooth,
package/src/internal.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import type {
2
+ Alarm,
3
+ AlarmCapabilities,
4
+ AlarmEventName,
2
5
  BluetoothCapabilities,
3
6
  BluetoothConnectOptions,
4
7
  BluetoothConnection,
@@ -18,6 +21,7 @@ import type {
18
21
  PushTokenInfo,
19
22
  PushTokenOptions,
20
23
  SafeInsets,
24
+ ScheduleAlarmInput,
21
25
  } from "./types"
22
26
 
23
27
  type PmateWindow = Window & {
@@ -43,6 +47,18 @@ export function readIsPmate() {
43
47
  return hasWindow() && !!(window as PmateWindow).isPmate
44
48
  }
45
49
 
50
+ function normalizedPlatform(info?: Pick<DeviceInfo, "platform"> | null) {
51
+ return info?.platform?.trim().toLowerCase() ?? ""
52
+ }
53
+
54
+ export function isAndroidDevice(info?: Pick<DeviceInfo, "platform"> | null) {
55
+ return normalizedPlatform(info) === "android"
56
+ }
57
+
58
+ export function isIOSDevice(info?: Pick<DeviceInfo, "platform"> | null) {
59
+ return normalizedPlatform(info) === "ios"
60
+ }
61
+
46
62
  async function callBridge<T>(functionName: string, params?: unknown): Promise<T | undefined> {
47
63
  try {
48
64
  return await (window as PmateWindow).PmateBridge?.call<T>(functionName, params)
@@ -112,7 +128,10 @@ export async function getNotificationStatus(): Promise<NotificationStatus> {
112
128
  export async function getPushToken(
113
129
  options?: PushTokenOptions
114
130
  ): Promise<PushTokenInfo | undefined> {
115
- return callBridge<PushTokenInfo>("notification.getPushToken", options ?? null)
131
+ if (!hasWindow() || !(window as PmateWindow).PmateBridge?.call) {
132
+ return undefined
133
+ }
134
+ return requireBridge<PushTokenInfo>("notification.getPushToken", options ?? null)
116
135
  }
117
136
 
118
137
  export async function pickFileBridge(): Promise<PickedFile[]> {
@@ -120,6 +139,50 @@ export async function pickFileBridge(): Promise<PickedFile[]> {
120
139
  return files ?? []
121
140
  }
122
141
 
142
+ export async function getAlarmCapabilities(): Promise<AlarmCapabilities> {
143
+ const capabilities = await callBridge<AlarmCapabilities>("alarm.getCapabilities")
144
+ return (
145
+ capabilities ?? {
146
+ supported: false,
147
+ systemAlarm: false,
148
+ appAlarm: false,
149
+ exact: false,
150
+ repeating: false,
151
+ notificationPermission: "unsupported",
152
+ }
153
+ )
154
+ }
155
+
156
+ export function scheduleAlarm(input: ScheduleAlarmInput): Promise<Alarm> {
157
+ return requireBridge<Alarm>("alarm.schedule", input)
158
+ }
159
+
160
+ export async function getAlarm(id: string): Promise<Alarm | undefined> {
161
+ return callBridge<Alarm>("alarm.get", { id })
162
+ }
163
+
164
+ export function listAlarms(): Promise<{ alarms: Alarm[] }> {
165
+ return requireBridge<{ alarms: Alarm[] }>("alarm.list")
166
+ }
167
+
168
+ export function cancelAlarm(id: string): Promise<{ cancelled: true }> {
169
+ return requireBridge<{ cancelled: true }>("alarm.cancel", { id })
170
+ }
171
+
172
+ export function cancelAllAlarms(): Promise<{ cancelled: true }> {
173
+ return requireBridge<{ cancelled: true }>("alarm.cancelAll")
174
+ }
175
+
176
+ export function onAlarmEvent(
177
+ eventName: AlarmEventName,
178
+ handler: (payload: unknown) => void
179
+ ): () => void {
180
+ if (!hasWindow() || !(window as PmateWindow).PmateBridge?.on) {
181
+ throw new Error("Pmate bridge event subscription is unavailable")
182
+ }
183
+ return (window as PmateWindow).PmateBridge!.on!(`alarm.${eventName}`, handler)
184
+ }
185
+
123
186
  export function getBluetoothCapabilities(): Promise<BluetoothCapabilities> {
124
187
  return requireBridge<BluetoothCapabilities>("bluetooth.getCapabilities")
125
188
  }
package/src/types.ts CHANGED
@@ -17,6 +17,7 @@ export interface DeviceInfo {
17
17
  systemVersion: string
18
18
  model: string
19
19
  idiom: string
20
+ manufacturer?: string
20
21
  }
21
22
 
22
23
  export interface DeviceInfoState {
@@ -61,6 +62,59 @@ export interface PushTokenOptions {
61
62
  providers?: PushProvider[]
62
63
  }
63
64
 
65
+ export type AlarmDeliveryMode = "systemAlarm" | "appAlarm"
66
+ export type AlarmDeliveryPreference =
67
+ | "preferSystemAlarm"
68
+ | "preferAppAlarm"
69
+ | "systemAlarmOnly"
70
+ export type AlarmPermissionState =
71
+ | "granted"
72
+ | "denied"
73
+ | "notDetermined"
74
+ | "unsupported"
75
+ export type AlarmRepeatRule =
76
+ | { type: "none" }
77
+ | { type: "interval"; intervalMs: number }
78
+ | { type: "daily"; timeOfDay: string; timezone?: string }
79
+ export type AlarmState = "scheduled" | "triggered" | "cancelled"
80
+ export type AlarmEventName = "triggered" | "cancelled" | "error"
81
+
82
+ export interface AlarmCapabilities {
83
+ supported: boolean
84
+ systemAlarm: boolean
85
+ appAlarm: boolean
86
+ exact: boolean
87
+ repeating: boolean
88
+ notificationPermission: AlarmPermissionState
89
+ minimumIntervalMs?: number
90
+ maximumScheduledCount?: number
91
+ }
92
+
93
+ export interface Alarm {
94
+ id: string
95
+ title?: string
96
+ body?: string
97
+ deliveryMode: AlarmDeliveryMode
98
+ scheduledAt: number
99
+ repeat: AlarmRepeatRule
100
+ payload?: Record<string, unknown>
101
+ state: AlarmState
102
+ createdAt: number
103
+ updatedAt: number
104
+ lastTriggeredAt?: number
105
+ nextTriggerAt?: number
106
+ }
107
+
108
+ export interface ScheduleAlarmInput {
109
+ id?: string
110
+ title?: string
111
+ body?: string
112
+ scheduledAt: number
113
+ repeat?: AlarmRepeatRule
114
+ deliveryPreference?: AlarmDeliveryPreference
115
+ payload?: Record<string, unknown>
116
+ }
117
+
64
118
  export type BluetoothTransport = "ble" | "classic"
65
119
  export type BluetoothBinaryEncoding = "base64" | "hex" | "utf-8"
66
120
  export type BluetoothEventName =