@glassly/engine 0.4.0-dev.1067 → 0.4.0-dev.1069
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/build/engine.d.ts +1 -0
- package/build/engine.d.ts.map +1 -1
- package/build/facades/permissions.d.ts.map +1 -1
- package/build/facades/permissions.js +0 -2
- package/build/facades/permissions.js.map +1 -1
- package/build/facades/phoneNotifications.d.ts +7 -0
- package/build/facades/phoneNotifications.d.ts.map +1 -1
- package/build/facades/phoneNotifications.js +6 -0
- package/build/facades/phoneNotifications.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +3 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +67 -1
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/notifications/miniappNotifications.d.ts +31 -0
- package/build/services/notifications/miniappNotifications.d.ts.map +1 -0
- package/build/services/notifications/miniappNotifications.js +24 -0
- package/build/services/notifications/miniappNotifications.js.map +1 -0
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +0 -8
- package/build/stores/settings.js.map +1 -1
- package/package.json +7 -7
- package/src/facades/permissions.ts +0 -2
- package/src/facades/phoneNotifications.ts +10 -0
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/index.ts +1 -0
- package/src/services/LocalMiniappRuntime.ts +79 -1
- package/src/services/notifications/miniappNotifications.ts +53 -0
- package/src/stores/settings.ts +0 -8
|
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
|
|
|
12
12
|
export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "0.4.0",
|
|
15
|
-
"releaseIdentity": "0.4.0-dev.
|
|
16
|
-
"releaseSetId": "glassly-0.4.0-dev.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.4.0-dev.1069",
|
|
16
|
+
"releaseSetId": "glassly-0.4.0-dev.1069",
|
|
17
|
+
"sourceCommit": "bcfef8eea3e7e87e3d1aeaec27cae011b55e5cf3",
|
|
18
18
|
"otaManifestUrl": null,
|
|
19
19
|
"otaManifestSha256": null
|
|
20
20
|
})
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type {
|
|
|
23
23
|
} from "./facades/reports"
|
|
24
24
|
export type {IslandNotification, IslandNotificationKind} from "./facades/notifications"
|
|
25
25
|
export type {PresentationOwner} from "./services/notifications/notificationPolicy"
|
|
26
|
+
export type {MiniappNotificationEvent} from "./services/notifications/miniappNotifications"
|
|
26
27
|
export {DEFAULT_HIDDEN_PACKAGES, isGatedByDevTools, isSystemMiniapp} from "./stores/appVisibility"
|
|
27
28
|
export type {WifiSearchResult} from "./facades/glassesWifi"
|
|
28
29
|
export type {IdentitySnapshot} from "./services/PairingIdentity"
|
|
@@ -83,6 +83,13 @@ import overlayPages from "./pages/OverlayPages"
|
|
|
83
83
|
import dashboardOpenTrace from "./debug/DashboardOpenTrace"
|
|
84
84
|
import {isAppForegrounded, isPhoneActive, onAppForegroundChange, onPhoneActivityChange} from "./PhoneActivity"
|
|
85
85
|
import {installedNotificationApps} from "./PhoneNotificationsSync"
|
|
86
|
+
import {
|
|
87
|
+
emitMiniappNotification,
|
|
88
|
+
MINIAPP_NOTIFICATION_CONTENT_MAX,
|
|
89
|
+
MINIAPP_NOTIFICATION_ID_MAX,
|
|
90
|
+
MINIAPP_NOTIFICATION_TITLE_MAX,
|
|
91
|
+
miniappNotificationId,
|
|
92
|
+
} from "./notifications/miniappNotifications"
|
|
86
93
|
import {MiniappIcons} from "./MiniappIcons"
|
|
87
94
|
import {pairedControllersFrom, readyControllersKey} from "./controllers"
|
|
88
95
|
import {
|
|
@@ -1513,6 +1520,12 @@ class LocalMiniappRuntime {
|
|
|
1513
1520
|
case MiniappRequestType.NOTIFICATION_APPS_LIST:
|
|
1514
1521
|
void this.handleNotificationAppsList(packageName, requestId)
|
|
1515
1522
|
break
|
|
1523
|
+
case MiniappRequestType.NOTIFICATION_POST:
|
|
1524
|
+
this.handleNotificationPost(packageName, payload, requestId)
|
|
1525
|
+
break
|
|
1526
|
+
case MiniappRequestType.NOTIFICATION_DISMISS:
|
|
1527
|
+
this.handleNotificationDismiss(packageName, payload, requestId)
|
|
1528
|
+
break
|
|
1516
1529
|
case MiniappRequestType.NATIVE_NAV:
|
|
1517
1530
|
this.handleNativeNav(packageName, payload, requestId)
|
|
1518
1531
|
break
|
|
@@ -2792,7 +2805,17 @@ class LocalMiniappRuntime {
|
|
|
2792
2805
|
return
|
|
2793
2806
|
}
|
|
2794
2807
|
try {
|
|
2795
|
-
|
|
2808
|
+
const posters = this.interopApps().filter(
|
|
2809
|
+
(app) => app.packageName && app.permissions?.some((permission) => permission.type === "POST_NOTIFICATIONS"),
|
|
2810
|
+
)
|
|
2811
|
+
const miniapps = await Promise.all(
|
|
2812
|
+
posters.map(async (app) => ({
|
|
2813
|
+
packageName: app.packageName,
|
|
2814
|
+
appName: app.name || app.packageName,
|
|
2815
|
+
icon: (await this.miniappIcons.read(app)) ?? null,
|
|
2816
|
+
})),
|
|
2817
|
+
)
|
|
2818
|
+
this.sendResult(packageName, requestId, true, [...(await installedNotificationApps()), ...miniapps])
|
|
2796
2819
|
} catch (err) {
|
|
2797
2820
|
this.sendResult(packageName, requestId, false, undefined, {
|
|
2798
2821
|
code: MiniappErrorCode.INTERNAL,
|
|
@@ -2801,6 +2824,60 @@ class LocalMiniappRuntime {
|
|
|
2801
2824
|
}
|
|
2802
2825
|
}
|
|
2803
2826
|
|
|
2827
|
+
private handleNotificationPost(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
|
|
2828
|
+
if (!this.requirePermission(packageName, requestId, "POST_NOTIFICATIONS", "to post notifications")) return
|
|
2829
|
+
const title = typeof payload.title === "string" ? payload.title.slice(0, MINIAPP_NOTIFICATION_TITLE_MAX) : ""
|
|
2830
|
+
const content =
|
|
2831
|
+
typeof payload.content === "string" ? payload.content.slice(0, MINIAPP_NOTIFICATION_CONTENT_MAX) : ""
|
|
2832
|
+
if (!title.trim() && !content.trim()) {
|
|
2833
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2834
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
2835
|
+
message: "A notification needs a title or content",
|
|
2836
|
+
})
|
|
2837
|
+
return
|
|
2838
|
+
}
|
|
2839
|
+
if (payload.id !== undefined && (typeof payload.id !== "string" || !payload.id.trim())) {
|
|
2840
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2841
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
2842
|
+
message: "A notification id must be a non-empty string",
|
|
2843
|
+
})
|
|
2844
|
+
return
|
|
2845
|
+
}
|
|
2846
|
+
const id =
|
|
2847
|
+
typeof payload.id === "string"
|
|
2848
|
+
? payload.id.trim().slice(0, MINIAPP_NOTIFICATION_ID_MAX)
|
|
2849
|
+
: `${Date.now().toString(36)}-${++this.notificationSeq}`
|
|
2850
|
+
const app = this.interopApps().find((candidate) => candidate.packageName === packageName)
|
|
2851
|
+
emitMiniappNotification({
|
|
2852
|
+
type: "posted",
|
|
2853
|
+
notificationId: miniappNotificationId(packageName, id),
|
|
2854
|
+
source: packageName,
|
|
2855
|
+
app: app?.name || packageName,
|
|
2856
|
+
title,
|
|
2857
|
+
content,
|
|
2858
|
+
timestamp: Date.now(),
|
|
2859
|
+
})
|
|
2860
|
+
this.sendResult(packageName, requestId, true, {id})
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
private handleNotificationDismiss(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
|
|
2864
|
+
if (!this.requirePermission(packageName, requestId, "POST_NOTIFICATIONS", "to dismiss notifications")) return
|
|
2865
|
+
if (typeof payload.id !== "string" || !payload.id.trim()) {
|
|
2866
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2867
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
2868
|
+
message: "dismiss needs the id post() returned",
|
|
2869
|
+
})
|
|
2870
|
+
return
|
|
2871
|
+
}
|
|
2872
|
+
emitMiniappNotification({
|
|
2873
|
+
type: "dismissed",
|
|
2874
|
+
notificationId: miniappNotificationId(packageName, payload.id.trim().slice(0, MINIAPP_NOTIFICATION_ID_MAX)),
|
|
2875
|
+
source: packageName,
|
|
2876
|
+
timestamp: Date.now(),
|
|
2877
|
+
})
|
|
2878
|
+
this.sendResult(packageName, requestId, true)
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2804
2881
|
/**
|
|
2805
2882
|
* Push bridged settings as they change: stored keys from the store, the
|
|
2806
2883
|
* derived keys whenever their inputs move (phone activity, the display,
|
|
@@ -6269,6 +6346,7 @@ class LocalMiniappRuntime {
|
|
|
6269
6346
|
}
|
|
6270
6347
|
|
|
6271
6348
|
private miniappIcons = new MiniappIcons()
|
|
6349
|
+
private notificationSeq = 0
|
|
6272
6350
|
|
|
6273
6351
|
private async handleMiniappsList(
|
|
6274
6352
|
packageName: string,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notifications miniapps post (`session.phone.notifications.post`) on their
|
|
3
|
+
* way into the host's phone-notification path. The runtime validates and
|
|
4
|
+
* emits here; the host subscribes through `engine.phoneNotifications` and
|
|
5
|
+
* feeds them to the same fan-out as the phone's own, with `system: false`
|
|
6
|
+
* and `source` set, so the dashboard, other readers and presentation treat
|
|
7
|
+
* them alike.
|
|
8
|
+
*/
|
|
9
|
+
export interface MiniappNotificationPosted {
|
|
10
|
+
type: "posted"
|
|
11
|
+
notificationId: string
|
|
12
|
+
source: string
|
|
13
|
+
app: string
|
|
14
|
+
title: string
|
|
15
|
+
content: string
|
|
16
|
+
timestamp: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface MiniappNotificationDismissed {
|
|
20
|
+
type: "dismissed"
|
|
21
|
+
notificationId: string
|
|
22
|
+
source: string
|
|
23
|
+
timestamp: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type MiniappNotificationEvent = MiniappNotificationPosted | MiniappNotificationDismissed
|
|
27
|
+
|
|
28
|
+
export const MINIAPP_NOTIFICATION_TITLE_MAX = 200
|
|
29
|
+
export const MINIAPP_NOTIFICATION_CONTENT_MAX = 2_000
|
|
30
|
+
export const MINIAPP_NOTIFICATION_ID_MAX = 128
|
|
31
|
+
|
|
32
|
+
const listeners = new Set<(event: MiniappNotificationEvent) => void>()
|
|
33
|
+
|
|
34
|
+
export function miniappNotificationId(source: string, id: string): string {
|
|
35
|
+
return `${source}:${id}`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function emitMiniappNotification(event: MiniappNotificationEvent): void {
|
|
39
|
+
for (const listener of listeners) {
|
|
40
|
+
try {
|
|
41
|
+
listener(event)
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.warn(`miniappNotifications: listener threw: ${(err as Error)?.message ?? err}`)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function onMiniappNotification(listener: (event: MiniappNotificationEvent) => void): () => void {
|
|
49
|
+
listeners.add(listener)
|
|
50
|
+
return () => {
|
|
51
|
+
listeners.delete(listener)
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/stores/settings.ts
CHANGED
|
@@ -132,13 +132,6 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
132
132
|
saveOnServer: true,
|
|
133
133
|
persist: true,
|
|
134
134
|
},
|
|
135
|
-
memomind_accessory_picker: {
|
|
136
|
-
key: "memomind_accessory_picker",
|
|
137
|
-
defaultValue: () => true,
|
|
138
|
-
writable: true,
|
|
139
|
-
saveOnServer: false,
|
|
140
|
-
persist: true,
|
|
141
|
-
},
|
|
142
135
|
debug_console: {
|
|
143
136
|
key: "debug_console",
|
|
144
137
|
defaultValue: () => false,
|
|
@@ -1274,7 +1267,6 @@ export const BLUETOOTH_SETTING_KEYS: string[] = [
|
|
|
1274
1267
|
SETTINGS.cfw_scene_renderer.key,
|
|
1275
1268
|
SETTINGS.cfw_fast_ble.key,
|
|
1276
1269
|
SETTINGS.perf_logs.key,
|
|
1277
|
-
SETTINGS.memomind_accessory_picker.key,
|
|
1278
1270
|
SETTINGS.ring_via_glasses.key,
|
|
1279
1271
|
SETTINGS.display_max_fps.key,
|
|
1280
1272
|
SETTINGS.twelve_hour_time.key,
|