@mentra/miniapp 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/README.md +259 -0
  2. package/dist/background/index.d.ts +60 -0
  3. package/dist/background/index.d.ts.map +1 -0
  4. package/dist/background/index.js +25 -0
  5. package/dist/background/index.js.map +1 -0
  6. package/dist/background/register.d.ts +38 -0
  7. package/dist/background/register.d.ts.map +1 -0
  8. package/dist/background/register.js +75 -0
  9. package/dist/background/register.js.map +1 -0
  10. package/dist/dev-reload.d.ts +21 -0
  11. package/dist/dev-reload.d.ts.map +1 -0
  12. package/dist/dev-reload.js +62 -0
  13. package/dist/dev-reload.js.map +1 -0
  14. package/dist/envelope.d.ts +23 -0
  15. package/dist/envelope.d.ts.map +1 -0
  16. package/dist/envelope.js +47 -0
  17. package/dist/envelope.js.map +1 -0
  18. package/dist/globals.d.ts +54 -0
  19. package/dist/globals.d.ts.map +1 -0
  20. package/dist/globals.js +12 -0
  21. package/dist/globals.js.map +1 -0
  22. package/dist/index.d.ts +59 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +31 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/modules/actions.d.ts +54 -0
  27. package/dist/modules/actions.d.ts.map +1 -0
  28. package/dist/modules/actions.js +122 -0
  29. package/dist/modules/actions.js.map +1 -0
  30. package/dist/modules/auth.d.ts +25 -0
  31. package/dist/modules/auth.d.ts.map +1 -0
  32. package/dist/modules/auth.js +52 -0
  33. package/dist/modules/auth.js.map +1 -0
  34. package/dist/modules/base64.d.ts +16 -0
  35. package/dist/modules/base64.d.ts.map +1 -0
  36. package/dist/modules/base64.js +92 -0
  37. package/dist/modules/base64.js.map +1 -0
  38. package/dist/modules/blob.d.ts +161 -0
  39. package/dist/modules/blob.d.ts.map +1 -0
  40. package/dist/modules/blob.js +277 -0
  41. package/dist/modules/blob.js.map +1 -0
  42. package/dist/modules/camera.d.ts +170 -0
  43. package/dist/modules/camera.d.ts.map +1 -0
  44. package/dist/modules/camera.js +116 -0
  45. package/dist/modules/camera.js.map +1 -0
  46. package/dist/modules/cloud.d.ts +34 -0
  47. package/dist/modules/cloud.d.ts.map +1 -0
  48. package/dist/modules/cloud.js +70 -0
  49. package/dist/modules/cloud.js.map +1 -0
  50. package/dist/modules/dashboard.d.ts +16 -0
  51. package/dist/modules/dashboard.d.ts.map +1 -0
  52. package/dist/modules/dashboard.js +27 -0
  53. package/dist/modules/dashboard.js.map +1 -0
  54. package/dist/modules/display.d.ts +106 -0
  55. package/dist/modules/display.d.ts.map +1 -0
  56. package/dist/modules/display.js +57 -0
  57. package/dist/modules/display.js.map +1 -0
  58. package/dist/modules/events.d.ts +160 -0
  59. package/dist/modules/events.d.ts.map +1 -0
  60. package/dist/modules/events.js +168 -0
  61. package/dist/modules/events.js.map +1 -0
  62. package/dist/modules/glasses.d.ts +28 -0
  63. package/dist/modules/glasses.d.ts.map +1 -0
  64. package/dist/modules/glasses.js +39 -0
  65. package/dist/modules/glasses.js.map +1 -0
  66. package/dist/modules/heading.d.ts +16 -0
  67. package/dist/modules/heading.d.ts.map +1 -0
  68. package/dist/modules/heading.js +20 -0
  69. package/dist/modules/heading.js.map +1 -0
  70. package/dist/modules/imu.d.ts +31 -0
  71. package/dist/modules/imu.d.ts.map +1 -0
  72. package/dist/modules/imu.js +40 -0
  73. package/dist/modules/imu.js.map +1 -0
  74. package/dist/modules/input.d.ts +34 -0
  75. package/dist/modules/input.d.ts.map +1 -0
  76. package/dist/modules/input.js +50 -0
  77. package/dist/modules/input.js.map +1 -0
  78. package/dist/modules/led.d.ts +35 -0
  79. package/dist/modules/led.d.ts.map +1 -0
  80. package/dist/modules/led.js +39 -0
  81. package/dist/modules/led.js.map +1 -0
  82. package/dist/modules/location.d.ts +27 -0
  83. package/dist/modules/location.d.ts.map +1 -0
  84. package/dist/modules/location.js +35 -0
  85. package/dist/modules/location.js.map +1 -0
  86. package/dist/modules/mic.d.ts +44 -0
  87. package/dist/modules/mic.d.ts.map +1 -0
  88. package/dist/modules/mic.js +67 -0
  89. package/dist/modules/mic.js.map +1 -0
  90. package/dist/modules/miniapps.d.ts +72 -0
  91. package/dist/modules/miniapps.d.ts.map +1 -0
  92. package/dist/modules/miniapps.js +48 -0
  93. package/dist/modules/miniapps.js.map +1 -0
  94. package/dist/modules/navigation.d.ts +326 -0
  95. package/dist/modules/navigation.d.ts.map +1 -0
  96. package/dist/modules/navigation.js +386 -0
  97. package/dist/modules/navigation.js.map +1 -0
  98. package/dist/modules/permissions.d.ts +58 -0
  99. package/dist/modules/permissions.d.ts.map +1 -0
  100. package/dist/modules/permissions.js +66 -0
  101. package/dist/modules/permissions.js.map +1 -0
  102. package/dist/modules/phone.d.ts +95 -0
  103. package/dist/modules/phone.d.ts.map +1 -0
  104. package/dist/modules/phone.js +110 -0
  105. package/dist/modules/phone.js.map +1 -0
  106. package/dist/modules/pivots/engine.d.ts +169 -0
  107. package/dist/modules/pivots/engine.d.ts.map +1 -0
  108. package/dist/modules/pivots/engine.js +779 -0
  109. package/dist/modules/pivots/engine.js.map +1 -0
  110. package/dist/modules/pivots/geometry.d.ts +84 -0
  111. package/dist/modules/pivots/geometry.d.ts.map +1 -0
  112. package/dist/modules/pivots/geometry.js +371 -0
  113. package/dist/modules/pivots/geometry.js.map +1 -0
  114. package/dist/modules/pivots/instructions.d.ts +139 -0
  115. package/dist/modules/pivots/instructions.d.ts.map +1 -0
  116. package/dist/modules/pivots/instructions.js +280 -0
  117. package/dist/modules/pivots/instructions.js.map +1 -0
  118. package/dist/modules/speaker.d.ts +169 -0
  119. package/dist/modules/speaker.d.ts.map +1 -0
  120. package/dist/modules/speaker.js +251 -0
  121. package/dist/modules/speaker.js.map +1 -0
  122. package/dist/modules/storage.d.ts +50 -0
  123. package/dist/modules/storage.d.ts.map +1 -0
  124. package/dist/modules/storage.js +99 -0
  125. package/dist/modules/storage.js.map +1 -0
  126. package/dist/modules/stream.d.ts +129 -0
  127. package/dist/modules/stream.d.ts.map +1 -0
  128. package/dist/modules/stream.js +52 -0
  129. package/dist/modules/stream.js.map +1 -0
  130. package/dist/modules/system.d.ts +45 -0
  131. package/dist/modules/system.d.ts.map +1 -0
  132. package/dist/modules/system.js +42 -0
  133. package/dist/modules/system.js.map +1 -0
  134. package/dist/modules/transcription.d.ts +75 -0
  135. package/dist/modules/transcription.d.ts.map +1 -0
  136. package/dist/modules/transcription.js +106 -0
  137. package/dist/modules/transcription.js.map +1 -0
  138. package/dist/modules/translation.d.ts +59 -0
  139. package/dist/modules/translation.d.ts.map +1 -0
  140. package/dist/modules/translation.js +119 -0
  141. package/dist/modules/translation.js.map +1 -0
  142. package/dist/modules/ui.d.ts +186 -0
  143. package/dist/modules/ui.d.ts.map +1 -0
  144. package/dist/modules/ui.js +293 -0
  145. package/dist/modules/ui.js.map +1 -0
  146. package/dist/protocol.d.ts +299 -0
  147. package/dist/protocol.d.ts.map +1 -0
  148. package/dist/protocol.js +325 -0
  149. package/dist/protocol.js.map +1 -0
  150. package/dist/react/MentraProvider.d.ts +33 -0
  151. package/dist/react/MentraProvider.d.ts.map +1 -0
  152. package/dist/react/MentraProvider.js +15 -0
  153. package/dist/react/MentraProvider.js.map +1 -0
  154. package/dist/react/MiniappHeader.d.ts +44 -0
  155. package/dist/react/MiniappHeader.d.ts.map +1 -0
  156. package/dist/react/MiniappHeader.js +32 -0
  157. package/dist/react/MiniappHeader.js.map +1 -0
  158. package/dist/react/index.d.ts +13 -0
  159. package/dist/react/index.d.ts.map +1 -0
  160. package/dist/react/index.js +9 -0
  161. package/dist/react/index.js.map +1 -0
  162. package/dist/react/useCapabilities.d.ts +26 -0
  163. package/dist/react/useCapabilities.d.ts.map +1 -0
  164. package/dist/react/useCapabilities.js +27 -0
  165. package/dist/react/useCapabilities.js.map +1 -0
  166. package/dist/react/useCapsuleHeaderStyle.d.ts +27 -0
  167. package/dist/react/useCapsuleHeaderStyle.d.ts.map +1 -0
  168. package/dist/react/useCapsuleHeaderStyle.js +36 -0
  169. package/dist/react/useCapsuleHeaderStyle.js.map +1 -0
  170. package/dist/react/useColorScheme.d.ts +18 -0
  171. package/dist/react/useColorScheme.d.ts.map +1 -0
  172. package/dist/react/useColorScheme.js +24 -0
  173. package/dist/react/useColorScheme.js.map +1 -0
  174. package/dist/react/useConnected.d.ts +17 -0
  175. package/dist/react/useConnected.d.ts.map +1 -0
  176. package/dist/react/useConnected.js +39 -0
  177. package/dist/react/useConnected.js.map +1 -0
  178. package/dist/react/useRpc.d.ts +29 -0
  179. package/dist/react/useRpc.d.ts.map +1 -0
  180. package/dist/react/useRpc.js +82 -0
  181. package/dist/react/useRpc.js.map +1 -0
  182. package/dist/react/useSafeArea.d.ts +21 -0
  183. package/dist/react/useSafeArea.d.ts.map +1 -0
  184. package/dist/react/useSafeArea.js +22 -0
  185. package/dist/react/useSafeArea.js.map +1 -0
  186. package/dist/session.d.ts +312 -0
  187. package/dist/session.d.ts.map +1 -0
  188. package/dist/session.js +653 -0
  189. package/dist/session.js.map +1 -0
  190. package/dist/sub-path-types.test-d.d.ts +28 -0
  191. package/dist/sub-path-types.test-d.d.ts.map +1 -0
  192. package/dist/sub-path-types.test-d.js +37 -0
  193. package/dist/sub-path-types.test-d.js.map +1 -0
  194. package/dist/transport/auto.d.ts +35 -0
  195. package/dist/transport/auto.d.ts.map +1 -0
  196. package/dist/transport/auto.js +125 -0
  197. package/dist/transport/auto.js.map +1 -0
  198. package/dist/transport/dispatch.d.ts +43 -0
  199. package/dist/transport/dispatch.d.ts.map +1 -0
  200. package/dist/transport/dispatch.js +91 -0
  201. package/dist/transport/dispatch.js.map +1 -0
  202. package/dist/transport/local-socket.d.ts +28 -0
  203. package/dist/transport/local-socket.d.ts.map +1 -0
  204. package/dist/transport/local-socket.js +80 -0
  205. package/dist/transport/local-socket.js.map +1 -0
  206. package/dist/transport/mock.d.ts +54 -0
  207. package/dist/transport/mock.d.ts.map +1 -0
  208. package/dist/transport/mock.js +207 -0
  209. package/dist/transport/mock.js.map +1 -0
  210. package/dist/transport/postmessage.d.ts +36 -0
  211. package/dist/transport/postmessage.d.ts.map +1 -0
  212. package/dist/transport/postmessage.js +78 -0
  213. package/dist/transport/postmessage.js.map +1 -0
  214. package/dist/transport/types.d.ts +25 -0
  215. package/dist/transport/types.d.ts.map +1 -0
  216. package/dist/transport/types.js +11 -0
  217. package/dist/transport/types.js.map +1 -0
  218. package/dist/ui/index.d.ts +98 -0
  219. package/dist/ui/index.d.ts.map +1 -0
  220. package/dist/ui/index.js +32 -0
  221. package/dist/ui/index.js.map +1 -0
  222. package/package.json +84 -0
  223. package/src/background/index.ts +152 -0
  224. package/src/background/register.ts +85 -0
  225. package/src/dev-reload.ts +60 -0
  226. package/src/envelope.ts +54 -0
  227. package/src/globals.ts +62 -0
  228. package/src/index.ts +171 -0
  229. package/src/modules/actions.ts +156 -0
  230. package/src/modules/auth.ts +68 -0
  231. package/src/modules/base64.ts +87 -0
  232. package/src/modules/blob.ts +341 -0
  233. package/src/modules/camera.ts +242 -0
  234. package/src/modules/cloud.ts +94 -0
  235. package/src/modules/dashboard.ts +31 -0
  236. package/src/modules/display.ts +122 -0
  237. package/src/modules/events.ts +291 -0
  238. package/src/modules/glasses.ts +44 -0
  239. package/src/modules/heading.ts +23 -0
  240. package/src/modules/imu.ts +44 -0
  241. package/src/modules/input.ts +71 -0
  242. package/src/modules/led.ts +61 -0
  243. package/src/modules/location.ts +39 -0
  244. package/src/modules/mic.ts +74 -0
  245. package/src/modules/miniapps.ts +90 -0
  246. package/src/modules/navigation.ts +670 -0
  247. package/src/modules/permissions.ts +84 -0
  248. package/src/modules/phone.ts +155 -0
  249. package/src/modules/pivots/engine.ts +863 -0
  250. package/src/modules/pivots/geometry.ts +409 -0
  251. package/src/modules/pivots/instructions.ts +343 -0
  252. package/src/modules/speaker.ts +335 -0
  253. package/src/modules/storage.ts +109 -0
  254. package/src/modules/stream.ts +163 -0
  255. package/src/modules/system.ts +76 -0
  256. package/src/modules/transcription.ts +145 -0
  257. package/src/modules/translation.ts +149 -0
  258. package/src/modules/ui.ts +498 -0
  259. package/src/protocol.ts +378 -0
  260. package/src/react/MentraProvider.tsx +50 -0
  261. package/src/react/MiniappHeader.tsx +122 -0
  262. package/src/react/index.ts +12 -0
  263. package/src/react/useCapabilities.ts +29 -0
  264. package/src/react/useCapsuleHeaderStyle.ts +54 -0
  265. package/src/react/useColorScheme.ts +26 -0
  266. package/src/react/useConnected.ts +47 -0
  267. package/src/react/useRpc.ts +106 -0
  268. package/src/react/useSafeArea.ts +40 -0
  269. package/src/session.ts +886 -0
  270. package/src/sub-path-types.test-d.ts +49 -0
  271. package/src/transport/auto.ts +143 -0
  272. package/src/transport/dispatch.ts +106 -0
  273. package/src/transport/local-socket.ts +93 -0
  274. package/src/transport/mock.ts +251 -0
  275. package/src/transport/postmessage.ts +95 -0
  276. package/src/transport/types.ts +26 -0
  277. package/src/ui/index.ts +122 -0
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @fileoverview PermissionsModule — manifest-declared permission introspection.
3
+ *
4
+ * Mirrors cloud SDK v3's PermissionsManager surface and semantics:
5
+ * permissions.has(type) — synchronous boolean
6
+ * permissions.getAll() — full PermissionRecord
7
+ * permissions.onUpdate(handler) — fires on cache change
8
+ * permissions.onPermissionError(handler) — typed handler for the existing
9
+ * PERMISSION_NOT_DECLARED error
10
+ *
11
+ * What "permission" means here. Same as v3: this module tracks
12
+ * **manifest-declared** permissions. `permissions.has("microphone") === true`
13
+ * means the miniapp's manifest.json declared MICROPHONE — it does NOT mean
14
+ * the user actually granted the OS permission. To detect OS-grant state,
15
+ * observe whether your subscriptions actually deliver events.
16
+ *
17
+ * OS-level grant state and `request(...)` are deferred to a future round.
18
+ * Their additions will land additively on this same module — `isGranted(...)`
19
+ * / `request(...)` alongside the existing `has(...)` / `getAll(...)` —
20
+ * without renaming today's surface.
21
+ */
22
+
23
+ import {MiniappErrorCode} from "../protocol"
24
+ import type {MiniappRequestError} from "../session"
25
+ import {MiniappSession} from "../session"
26
+ import type {PermissionRecord, PermissionType} from "../session"
27
+ import type {UnsubscribeFn} from "./events"
28
+
29
+ export interface PermissionErrorEvent {
30
+ /** The error code. Always PERMISSION_NOT_DECLARED today; reserved for future codes. */
31
+ code: string
32
+ message: string
33
+ /** The manifest permission name (UPPER_CASE) that was missing. */
34
+ permission?: string
35
+ /** The subscription / operation that triggered the rejection. */
36
+ subscription?: string
37
+ operation?: string
38
+ }
39
+
40
+ export class PermissionsModule {
41
+ /** Local handlers for onUpdate. Session emitter handles the fan-out. */
42
+ constructor(private readonly session: MiniappSession) {}
43
+
44
+ /** True iff the named permission is declared in the miniapp's manifest. */
45
+ has(type: PermissionType): boolean {
46
+ return this.session._getPermissions()[type] === true
47
+ }
48
+
49
+ /** Full record of declared permissions. Fresh shallow copy. */
50
+ getAll(): PermissionRecord {
51
+ return this.session._getPermissions()
52
+ }
53
+
54
+ /**
55
+ * Subscribe to declared-permission updates. Fires when the cached record
56
+ * changes — usually on CONNECT_ACK, or when the phone pushes a
57
+ * PERMISSIONS_UPDATE (e.g. dev miniapp re-scanned with updated manifest).
58
+ *
59
+ * Does NOT fire immediately with the current value — call getAll()
60
+ * separately if you want the seed.
61
+ */
62
+ onUpdate(handler: (perms: PermissionRecord) => void): UnsubscribeFn {
63
+ return this.session.on("permissions", handler)
64
+ }
65
+
66
+ /**
67
+ * Subscribe to typed PERMISSION_NOT_DECLARED errors. Sugar over the
68
+ * existing session "error" event, filtered to the permission-error code.
69
+ */
70
+ onPermissionError(handler: (err: PermissionErrorEvent) => void): UnsubscribeFn {
71
+ return this.session.on("error", (e) => {
72
+ const maybe = e as Error & Partial<MiniappRequestError> & Record<string, unknown>
73
+ if (maybe?.code === MiniappErrorCode.PERMISSION_NOT_DECLARED) {
74
+ handler({
75
+ code: String(maybe.code),
76
+ message: String(maybe.message ?? ""),
77
+ permission: maybe.permission as string | undefined,
78
+ subscription: maybe.subscription as string | undefined,
79
+ operation: maybe.operation as string | undefined,
80
+ })
81
+ }
82
+ })
83
+ }
84
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @fileoverview PhoneModule — phone device-state events.
3
+ *
4
+ * Mirrors cloud SDK v3's PhoneManager structure. Sub-namespaced by concern:
5
+ *
6
+ * session.phone.notifications.{on, hasPermission, stop}
7
+ * session.phone.calendar.{listEvents, hasPermission}
8
+ * session.phone.onBattery(...) // stays flat
9
+ *
10
+ * Imperative phone-OS calls (share, openUrl, copyToClipboard, download) live
11
+ * on `session.system` — different shape (one-shot calls vs. event subs) so
12
+ * we don't conflate them.
13
+ *
14
+ * `phone.notifications.onDismissed` is Android-only. iOS doesn't expose
15
+ * notification-dismiss callbacks to apps (Apple privacy restriction);
16
+ * subscribing on iOS is a no-op even though the API is present.
17
+ */
18
+
19
+ import {MiniappRequestType, MiniappStreamType} from "../protocol"
20
+ import {MiniappSession} from "../session"
21
+ import type {BatteryData, NotificationDismissedData, PhoneNotificationData, UnsubscribeFn} from "./events"
22
+
23
+ class TrackedSubs {
24
+ private readonly unsubs = new Set<UnsubscribeFn>()
25
+
26
+ protected track(unsub: UnsubscribeFn): UnsubscribeFn {
27
+ this.unsubs.add(unsub)
28
+ return () => {
29
+ this.unsubs.delete(unsub)
30
+ unsub()
31
+ }
32
+ }
33
+
34
+ stop(): void {
35
+ for (const u of this.unsubs) {
36
+ try {
37
+ u()
38
+ } catch {
39
+ /* ignore */
40
+ }
41
+ }
42
+ this.unsubs.clear()
43
+ }
44
+ }
45
+
46
+ export class PhoneNotificationsModule extends TrackedSubs {
47
+ constructor(private readonly session: MiniappSession) {
48
+ super()
49
+ }
50
+
51
+ on(handler: (data: PhoneNotificationData) => void): UnsubscribeFn {
52
+ return this.track(this.session._subscribe(MiniappStreamType.PHONE_NOTIFICATION, handler as (data: unknown) => void))
53
+ }
54
+
55
+ /**
56
+ * Subscribe to dismiss events for phone notifications. Fires when the user
57
+ * dismisses (swipes away or clears) a notification.
58
+ *
59
+ * **Android only.** iOS does not expose dismiss callbacks to apps (Apple
60
+ * privacy restriction); subscribing on iOS succeeds but no events ever
61
+ * fire. The matching `notifications.on()` post-event still works on both
62
+ * platforms.
63
+ */
64
+ onDismissed(handler: (data: NotificationDismissedData) => void): UnsubscribeFn {
65
+ return this.track(
66
+ this.session._subscribe(MiniappStreamType.PHONE_NOTIFICATION_DISMISSED, handler as (data: unknown) => void),
67
+ )
68
+ }
69
+
70
+ /** True iff `READ_NOTIFICATIONS` is declared in the miniapp's manifest. */
71
+ get hasPermission(): boolean {
72
+ return this.session._hasManifestPermission("READ_NOTIFICATIONS")
73
+ }
74
+ }
75
+
76
+ export interface CalendarListOptions {
77
+ /** Inclusive start of the query window. */
78
+ startsAt: string | Date
79
+ /** Exclusive end of the query window. Must be after startsAt. */
80
+ endsAt: string | Date
81
+ /** Maximum events to return. Defaults to 50 and may not exceed 100. */
82
+ limit?: number
83
+ }
84
+
85
+ export interface CalendarEvent {
86
+ /** Stable occurrence id, unique across calendars and recurring instances. */
87
+ id: string
88
+ calendarId: string
89
+ title: string
90
+ /** ISO 8601 start time. All-day events preserve their calendar timezone offset. */
91
+ startsAt: string
92
+ /** ISO 8601 end time. All-day events preserve their calendar timezone offset. */
93
+ endsAt: string
94
+ timezone?: string
95
+ allDay: boolean
96
+ location?: string
97
+ notes?: string
98
+ url?: string
99
+ /** Deduplicated HTTPS links found in the event URL, location, and notes. */
100
+ links: string[]
101
+ }
102
+
103
+ export interface CalendarListResult {
104
+ events: CalendarEvent[]
105
+ /** True when more matching events existed than the requested limit. */
106
+ truncated: boolean
107
+ }
108
+
109
+ export class PhoneCalendarModule {
110
+ constructor(private readonly session: MiniappSession) {}
111
+
112
+ /**
113
+ * Read calendar events in a bounded window. CALENDAR must be declared in
114
+ * miniapp.json and granted before the miniapp opens.
115
+ */
116
+ listEvents(options: CalendarListOptions): Promise<CalendarListResult> {
117
+ const startsAt = normalizeCalendarDate(options?.startsAt, "startsAt")
118
+ const endsAt = normalizeCalendarDate(options?.endsAt, "endsAt")
119
+ return this.session.sendRequest<CalendarListResult>({
120
+ type: MiniappRequestType.CALENDAR_LIST_EVENTS,
121
+ startsAt,
122
+ endsAt,
123
+ ...(options.limit === undefined ? {} : {limit: options.limit}),
124
+ })
125
+ }
126
+
127
+ /** True iff `CALENDAR` is declared in the miniapp's manifest. */
128
+ get hasPermission(): boolean {
129
+ return this.session._hasManifestPermission("CALENDAR")
130
+ }
131
+ }
132
+
133
+ function normalizeCalendarDate(value: string | Date | undefined, field: string): string {
134
+ const date = value instanceof Date ? value : new Date(value ?? "")
135
+ if (Number.isNaN(date.getTime())) throw new TypeError(`${field} must be a valid Date or ISO 8601 string`)
136
+ return date.toISOString()
137
+ }
138
+
139
+ export class PhoneModule {
140
+ public readonly notifications: PhoneNotificationsModule
141
+ public readonly calendar: PhoneCalendarModule
142
+
143
+ constructor(private readonly session: MiniappSession) {
144
+ this.notifications = new PhoneNotificationsModule(session)
145
+ this.calendar = new PhoneCalendarModule(session)
146
+ }
147
+
148
+ /**
149
+ * Phone battery events. Stays flat (not sub-namespaced) — single event,
150
+ * no extra surface.
151
+ */
152
+ onBattery(handler: (data: BatteryData) => void): UnsubscribeFn {
153
+ return this.session._subscribe(MiniappStreamType.PHONE_BATTERY, handler as (data: unknown) => void)
154
+ }
155
+ }