@glassly/engine 0.4.0-dev.1038 → 0.4.0-dev.1039
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 -1
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +1 -1
- package/build/engine.js.map +1 -1
- package/build/facades/glasses.js +1 -1
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/providerKeys.d.ts +1 -1
- package/build/facades/providerKeys.js +1 -1
- package/build/facades/providerKeys.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts.map +1 -1
- package/build/react/useMentraLiveOta.js.map +1 -1
- package/build/runtime/config.d.ts.map +1 -1
- package/build/runtime/config.js.map +1 -1
- package/build/services/AiTierResolution.d.ts +1 -1
- package/build/services/AiTierResolution.d.ts.map +1 -1
- package/build/services/AiTierResolution.js.map +1 -1
- package/build/services/AutomaticReportResult.d.ts.map +1 -1
- package/build/services/AutomaticReportResult.js.map +1 -1
- package/build/services/GestureDotsService.js +1 -1
- package/build/services/GestureDotsService.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts.map +1 -1
- package/build/services/HotspotOtaTransport.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +5 -2
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +53 -22
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/NativeNavigationService.d.ts.map +1 -1
- package/build/services/NativeNavigationService.js.map +1 -1
- package/build/services/NavigationHandlers.d.ts +1 -1
- package/build/services/NavigationHandlers.js +2 -2
- package/build/services/NavigationHandlers.js.map +1 -1
- package/build/services/NavigationService.d.ts +2 -2
- package/build/services/NavigationService.d.ts.map +1 -1
- package/build/services/NavigationService.js +11 -11
- package/build/services/NavigationService.js.map +1 -1
- package/build/services/PairingIdentity.d.ts.map +1 -1
- package/build/services/PairingIdentity.js.map +1 -1
- package/build/services/PhoneCalendarService.d.ts.map +1 -1
- package/build/services/PhoneCalendarService.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +2 -1
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/ProviderKeyValidation.d.ts +1 -1
- package/build/services/ProviderKeyValidation.js +1 -1
- package/build/services/ProviderKeyValidation.js.map +1 -1
- package/build/services/STTModelManager.d.ts.map +1 -1
- package/build/services/STTModelManager.js +1 -6
- package/build/services/STTModelManager.js.map +1 -1
- package/build/services/TranscriptionRouting.d.ts +3 -0
- package/build/services/TranscriptionRouting.d.ts.map +1 -1
- package/build/services/TranscriptionRouting.js +14 -0
- package/build/services/TranscriptionRouting.js.map +1 -1
- package/build/services/UIRouter.d.ts.map +1 -1
- package/build/services/UIRouter.js.map +1 -1
- package/build/services/gestureDotGlyphs.d.ts.map +1 -1
- package/build/services/gestureDotGlyphs.js.map +1 -1
- package/build/services/manifestActions.d.ts.map +1 -1
- package/build/services/manifestActions.js.map +1 -1
- package/build/services/notificationAppPayload.d.ts +14 -0
- package/build/services/notificationAppPayload.d.ts.map +1 -0
- package/build/services/notificationAppPayload.js +15 -0
- package/build/services/notificationAppPayload.js.map +1 -0
- package/build/services/settingsBridge.d.ts.map +1 -1
- package/build/services/settingsBridge.js.map +1 -1
- package/build/stores/appVisibility.d.ts.map +1 -1
- package/build/stores/appVisibility.js.map +1 -1
- package/build/stores/gallerySync.d.ts.map +1 -1
- package/build/stores/gallerySync.js.map +1 -1
- package/build/stores/settings.js +1 -1
- package/build/stores/settings.js.map +1 -1
- package/build/utils/display/scene/svgPath.js.map +1 -1
- package/build/utils/memory/search.d.ts.map +1 -1
- package/build/utils/memory/search.js +17 -7
- package/build/utils/memory/search.js.map +1 -1
- package/package.json +7 -7
- package/src/engine.ts +1 -1
- package/src/facades/glasses.ts +1 -1
- package/src/facades/providerKeys.ts +1 -1
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/react/useMentraLiveOta.ts +1 -4
- package/src/runtime/config.ts +1 -6
- package/src/services/AiTierResolution.ts +1 -1
- package/src/services/AutomaticReportResult.ts +1 -3
- package/src/services/GestureDotsService.ts +1 -1
- package/src/services/HotspotOtaTransport.ts +1 -4
- package/src/services/LocalMiniappRuntime.ts +65 -23
- package/src/services/LocalSttFallbackCoordinator.ts +1 -5
- package/src/services/NativeNavigationService.ts +1 -2
- package/src/services/NavigationHandlers.ts +2 -2
- package/src/services/NavigationService.ts +12 -11
- package/src/services/PairingIdentity.ts +1 -3
- package/src/services/PhoneCalendarService.ts +1 -3
- package/src/services/PhoneNotificationsSync.ts +2 -1
- package/src/services/PhoneStreamCoordinator.ts +1 -2
- package/src/services/ProviderKeyValidation.ts +1 -1
- package/src/services/STTModelManager.ts +1 -6
- package/src/services/TranscriptionRouting.ts +18 -0
- package/src/services/UIRouter.ts +3 -9
- package/src/services/gestureDotGlyphs.ts +10 -5
- package/src/services/manifestActions.ts +2 -1
- package/src/services/notificationAppPayload.ts +15 -0
- package/src/services/settingsBridge.ts +1 -2
- package/src/stores/appVisibility.ts +2 -5
- package/src/stores/gallerySync.ts +1 -7
- package/src/stores/settings.ts +1 -1
- package/src/utils/display/scene/svgPath.ts +1 -1
- package/src/utils/memory/search.ts +17 -7
|
@@ -211,7 +211,7 @@ class NavigationService {
|
|
|
211
211
|
const mapboxRenderToken = await resolveMapboxRenderToken()
|
|
212
212
|
if (!mapboxRenderToken) {
|
|
213
213
|
const error =
|
|
214
|
-
"No Mapbox token available — add your key in Settings > API Keys" +
|
|
214
|
+
"No Mapbox token available — add your key in Settings > Privacy > API Keys" +
|
|
215
215
|
" (required while Glassly Cloud is disabled or unreachable)"
|
|
216
216
|
console.warn(`${LOG_TAG}: start blocked — ${error}`)
|
|
217
217
|
return {ok: false, error}
|
|
@@ -329,7 +329,7 @@ class NavigationService {
|
|
|
329
329
|
* Compute one or more routes without starting a trip.
|
|
330
330
|
*
|
|
331
331
|
* Reached from the miniapp bridge (NavigationHandlers.handleComputeRoute)
|
|
332
|
-
* when the user has saved their own Mapbox key in Settings > API Keys —
|
|
332
|
+
* when the user has saved their own Mapbox key in Settings > Privacy > API Keys —
|
|
333
333
|
* that key exists so navigation works without the cloud. Without a user
|
|
334
334
|
* key the bridge uses the v2 cloud maps service, which holds a provider
|
|
335
335
|
* token server-side and caches results. Implemented by
|
|
@@ -379,7 +379,7 @@ class NavigationService {
|
|
|
379
379
|
return !!resolveMapboxAccessToken()
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
/** True when the user saved their own Mapbox key in Settings > API Keys. */
|
|
382
|
+
/** True when the user saved their own Mapbox key in Settings > Privacy > API Keys. */
|
|
383
383
|
public hasUserMapboxKey(): boolean {
|
|
384
384
|
return !!userMapboxApiKey()
|
|
385
385
|
}
|
|
@@ -501,7 +501,7 @@ export default navigationService
|
|
|
501
501
|
// ---------------------------------------------------------------------------
|
|
502
502
|
|
|
503
503
|
// Routes + Geocoding go DIRECT to Mapbox from the phone process ONLY when the
|
|
504
|
-
// user saved their own key (Settings > API Keys) — "use my account". Without
|
|
504
|
+
// user saved their own key (Settings > Privacy > API Keys) — "use my account". Without
|
|
505
505
|
// one, callers (NavigationHandlers) route these operations through the v2
|
|
506
506
|
// cloud maps proxy instead; the binary ships no baked Mapbox key.
|
|
507
507
|
const MAPBOX_DIRECTIONS_BASE = "https://api.mapbox.com/directions/v5/mapbox"
|
|
@@ -532,7 +532,7 @@ function mapboxToken(): string {
|
|
|
532
532
|
|
|
533
533
|
/**
|
|
534
534
|
* Phone-side helper: hit the Mapbox Directions API directly with the user's own
|
|
535
|
-
* key (Settings > API Keys). Preferred over the v2 cloud maps service whenever
|
|
535
|
+
* key (Settings > Privacy > API Keys). Preferred over the v2 cloud maps service whenever
|
|
536
536
|
* that key is set, so routing works without the cloud. Lives here
|
|
537
537
|
* (not in Kotlin) so it's platform-independent across the JS bridge.
|
|
538
538
|
* Returns the SDK-shaped result with primary + alternates.
|
|
@@ -583,7 +583,8 @@ async function computeRouteViaRoutesApi(payload: Record<string, unknown>): Promi
|
|
|
583
583
|
}
|
|
584
584
|
|
|
585
585
|
const token = mapboxToken()
|
|
586
|
-
if (!token)
|
|
586
|
+
if (!token)
|
|
587
|
+
return {ok: false, error: "computeRoute: no Mapbox key saved (add yours in Settings > Privacy > API Keys)"}
|
|
587
588
|
|
|
588
589
|
// Mapbox path is a semicolon-joined `lng,lat` list: origin then each stop.
|
|
589
590
|
const coords = [`${oLng},${oLat}`, ...stops.map((s) => `${s.lng},${s.lat}`)].join(";")
|
|
@@ -739,7 +740,7 @@ function mapboxManeuverToKind(type?: string, modifier?: string): string | undefi
|
|
|
739
740
|
|
|
740
741
|
/**
|
|
741
742
|
* Reverse-geocode a coordinate via the Mapbox Geocoding v6 API directly, using
|
|
742
|
-
* the user's own key (Settings > API Keys). Preferred over the v2 cloud maps
|
|
743
|
+
* the user's own key (Settings > Privacy > API Keys). Preferred over the v2 cloud maps
|
|
743
744
|
* service whenever that key is set, so pin labels work without the cloud.
|
|
744
745
|
*
|
|
745
746
|
* Returns the road/street name (e.g. "Octavia Blvd") plus the full formatted
|
|
@@ -767,7 +768,7 @@ async function reverseGeocodeRoadViaGeocodingApi(coord: {lat: number; lng: numbe
|
|
|
767
768
|
if (!token)
|
|
768
769
|
return {
|
|
769
770
|
ok: false,
|
|
770
|
-
error: "reverseGeocode: no Mapbox key saved (add yours in Settings > API Keys)",
|
|
771
|
+
error: "reverseGeocode: no Mapbox key saved (add yours in Settings > Privacy > API Keys)",
|
|
771
772
|
}
|
|
772
773
|
const params = new URLSearchParams({
|
|
773
774
|
longitude: String(coord.lng),
|
|
@@ -813,7 +814,7 @@ async function reverseGeocodeRoadViaGeocodingApi(coord: {lat: number; lng: numbe
|
|
|
813
814
|
|
|
814
815
|
/**
|
|
815
816
|
* Type-ahead place search straight from the device via Mapbox Search Box,
|
|
816
|
-
* using the user's own key (Settings > API Keys). This is the offline-from-
|
|
817
|
+
* using the user's own key (Settings > Privacy > API Keys). This is the offline-from-
|
|
817
818
|
* the-cloud path: with a key saved, place search works with no runtime
|
|
818
819
|
* involvement at all.
|
|
819
820
|
*
|
|
@@ -840,7 +841,7 @@ async function placeAutocompleteViaSearchBox(
|
|
|
840
841
|
if (!token) {
|
|
841
842
|
return {
|
|
842
843
|
ok: false,
|
|
843
|
-
error: "placeAutocomplete: no Mapbox key saved (add yours in Settings > API Keys)",
|
|
844
|
+
error: "placeAutocomplete: no Mapbox key saved (add yours in Settings > Privacy > API Keys)",
|
|
844
845
|
}
|
|
845
846
|
}
|
|
846
847
|
const params = new URLSearchParams({
|
|
@@ -904,7 +905,7 @@ async function placeDetailsViaSearchBox(
|
|
|
904
905
|
if (!token) {
|
|
905
906
|
return {
|
|
906
907
|
ok: false,
|
|
907
|
-
error: "placeDetails: no Mapbox key saved (add yours in Settings > API Keys)",
|
|
908
|
+
error: "placeDetails: no Mapbox key saved (add yours in Settings > Privacy > API Keys)",
|
|
908
909
|
}
|
|
909
910
|
}
|
|
910
911
|
const params = new URLSearchParams({access_token: token, session_token: sessionToken})
|
|
@@ -40,9 +40,7 @@ import {useSettingsStore, SETTINGS} from "../stores/settings"
|
|
|
40
40
|
import {DeviceTypes} from "../types"
|
|
41
41
|
|
|
42
42
|
export type IdentitySnapshot =
|
|
43
|
-
| {kind: "
|
|
44
|
-
| {kind: "pending"; model: string}
|
|
45
|
-
| {kind: "paired"; model: string; name: string; address?: string}
|
|
43
|
+
{kind: "none"} | {kind: "pending"; model: string} | {kind: "paired"; model: string; name: string; address?: string}
|
|
46
44
|
|
|
47
45
|
// Identity keys hold model/name strings; anything else (legacy null, a stray
|
|
48
46
|
// non-string) reads as absent, matching native currentDefaultDevice()'s
|
|
@@ -14,9 +14,7 @@ import {
|
|
|
14
14
|
|
|
15
15
|
export {PhoneCalendarError} from "./PhoneCalendarHelpers"
|
|
16
16
|
|
|
17
|
-
type CalendarPermissionStatus = Awaited<
|
|
18
|
-
ReturnType<typeof Calendar.getCalendarPermissionsAsync>
|
|
19
|
-
>["status"]
|
|
17
|
+
type CalendarPermissionStatus = Awaited<ReturnType<typeof Calendar.getCalendarPermissionsAsync>>["status"]
|
|
20
18
|
|
|
21
19
|
/**
|
|
22
20
|
* expo-calendar reports anything below EventKit full access as not granted,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {notificationAppPayload} from "./notificationAppPayload"
|
|
1
2
|
/**
|
|
2
3
|
* Phone-notifications sync — engine-owned, started by `engine.start()`. Keeps
|
|
3
4
|
* three things in step with settings and the connected glasses, for any host:
|
|
@@ -78,7 +79,7 @@ export function getKnownNotificationApps(): NotificationApp[] {
|
|
|
78
79
|
export function installedNotificationApps(): Promise<
|
|
79
80
|
Array<{packageName: string; appName: string; icon: string | null}>
|
|
80
81
|
> {
|
|
81
|
-
if (Platform.OS === "android") return CrustModule.getInstalledApps()
|
|
82
|
+
if (Platform.OS === "android") return CrustModule.getInstalledApps().then(notificationAppPayload)
|
|
82
83
|
if (Platform.OS !== "ios") return Promise.resolve([])
|
|
83
84
|
return Promise.resolve(
|
|
84
85
|
getKnownNotificationApps().map((app) => ({packageName: app.appId, appName: app.displayName, icon: null})),
|
|
@@ -339,8 +339,7 @@ export class PhoneStreamCoordinator {
|
|
|
339
339
|
// block subsequent start/stop transitions on this coordinator.
|
|
340
340
|
assertGlassesConnected()
|
|
341
341
|
type JoinDecision =
|
|
342
|
-
|
|
343
|
-
| {kind: "fresh"; entry: ManagedEntry}
|
|
342
|
+
{kind: "join"; entry: ManagedEntry; immediate: ManagedStartResult | null} | {kind: "fresh"; entry: ManagedEntry}
|
|
344
343
|
|
|
345
344
|
const decision = await this.runExclusive(async (): Promise<JoinDecision> => {
|
|
346
345
|
if (this.current && this.current.kind === "unmanaged") {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ProviderKeyValidation
|
|
3
3
|
*
|
|
4
4
|
* Cheap validate-before-save probes for the AI/voice provider keys on the
|
|
5
|
-
* Keys screen (Settings > API Keys), mirroring validateMapboxApiKey's shape:
|
|
5
|
+
* Keys screen (Settings > Privacy > API Keys), mirroring validateMapboxApiKey's shape:
|
|
6
6
|
* each probe hits the provider's cheapest authenticated read endpoint (no
|
|
7
7
|
* metered usage), maps auth failures to `invalid_key`, and maps everything
|
|
8
8
|
* else to `network` so the caller can offer "save anyway".
|
|
@@ -151,12 +151,7 @@ class STTModelManager {
|
|
|
151
151
|
fileName: "sherpa-onnx-nemo-streaming-fast-conformer-transducer-en-480ms-int8",
|
|
152
152
|
size: 101 * 1024 * 1024,
|
|
153
153
|
type: "transducer",
|
|
154
|
-
requiredFiles: [
|
|
155
|
-
"encoder.int8.onnx",
|
|
156
|
-
"decoder.int8.onnx",
|
|
157
|
-
"joiner.int8.onnx",
|
|
158
|
-
"tokens.txt",
|
|
159
|
-
],
|
|
154
|
+
requiredFiles: ["encoder.int8.onnx", "decoder.int8.onnx", "joiner.int8.onnx", "tokens.txt"],
|
|
160
155
|
languageCode: "en-US",
|
|
161
156
|
},
|
|
162
157
|
// NVIDIA Nemotron streaming ASR. These are model choices rather than plain
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
import type {TranscriptionSubscription} from "@glassly/cloud-protocol"
|
|
2
|
+
|
|
3
|
+
/** Match a provider result to a logical miniapp subscription. */
|
|
4
|
+
export function matchesTranscriptionSubscription(
|
|
5
|
+
stream: string,
|
|
6
|
+
resolvedStream: string,
|
|
7
|
+
subscription: TranscriptionSubscription,
|
|
8
|
+
): boolean {
|
|
9
|
+
const prefix = "transcription:"
|
|
10
|
+
if (!stream.startsWith(prefix) || !resolvedStream.startsWith(prefix)) return false
|
|
11
|
+
if (subscription.language.mode === "specific") return stream === `${prefix}${subscription.language.code}`
|
|
12
|
+
if (stream === `${prefix}auto`) return true
|
|
13
|
+
// Providers detect ISO language codes; miniapps request regional BCP-47 tags.
|
|
14
|
+
// Unknown language stays auto-only until the recognizer identifies it.
|
|
15
|
+
const detected = resolvedStream.slice(prefix.length).split("-")[0].toLowerCase()
|
|
16
|
+
return detected !== "auto" && detected !== "" && stream.slice(prefix.length).split("-")[0].toLowerCase() === detected
|
|
17
|
+
}
|
|
18
|
+
|
|
1
19
|
export interface TranscriptionRouteSummary {
|
|
2
20
|
hasCloudSubscriber: boolean
|
|
3
21
|
hasForceLocalSubscriber: boolean
|
package/src/services/UIRouter.ts
CHANGED
|
@@ -193,9 +193,7 @@ export class UIRouter {
|
|
|
193
193
|
const cancel = {type: "cancel", requestId: uiSendPayload.requestId}
|
|
194
194
|
const literal = JSON.stringify(cancel)
|
|
195
195
|
const escaped = JSON.stringify(literal)
|
|
196
|
-
binding.inject(
|
|
197
|
-
`if (window.__host && window.__host.recv) window.__host.recv(JSON.parse(${escaped})); true;`,
|
|
198
|
-
)
|
|
196
|
+
binding.inject(`if (window.__host && window.__host.recv) window.__host.recv(JSON.parse(${escaped})); true;`)
|
|
199
197
|
return
|
|
200
198
|
}
|
|
201
199
|
const outbound: Record<string, unknown> = {
|
|
@@ -207,9 +205,7 @@ export class UIRouter {
|
|
|
207
205
|
if (typeof uiSendPayload.requestId === "string") outbound.requestId = uiSendPayload.requestId
|
|
208
206
|
const literal = JSON.stringify(outbound)
|
|
209
207
|
const escaped = JSON.stringify(literal)
|
|
210
|
-
binding.inject(
|
|
211
|
-
`if (window.__host && window.__host.recv) window.__host.recv(JSON.parse(${escaped})); true;`,
|
|
212
|
-
)
|
|
208
|
+
binding.inject(`if (window.__host && window.__host.recv) window.__host.recv(JSON.parse(${escaped})); true;`)
|
|
213
209
|
}
|
|
214
210
|
|
|
215
211
|
/**
|
|
@@ -222,9 +218,7 @@ export class UIRouter {
|
|
|
222
218
|
if (!binding) return
|
|
223
219
|
const literal = JSON.stringify(frame)
|
|
224
220
|
const escaped = JSON.stringify(literal)
|
|
225
|
-
binding.inject(
|
|
226
|
-
`if (window.__host && window.__host.recv) window.__host.recv(JSON.parse(${escaped})); true;`,
|
|
227
|
-
)
|
|
221
|
+
binding.inject(`if (window.__host && window.__host.recv) window.__host.recv(JSON.parse(${escaped})); true;`)
|
|
228
222
|
}
|
|
229
223
|
|
|
230
224
|
/**
|
|
@@ -4,18 +4,23 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export const GESTURE_DOT_GLYPH_SIZE = 24
|
|
6
6
|
|
|
7
|
-
export type GestureDotGlyph =
|
|
7
|
+
export type GestureDotGlyph =
|
|
8
|
+
"dot" | "double" | "ring" | "doubleRing" | "up" | "down" | "left" | "right" | "hold" | "holdRing" | "blank"
|
|
8
9
|
|
|
9
10
|
export const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string> = {
|
|
10
11
|
dot: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALklEQVR4nM2QsQ0AAAjC/P/pmrhqZ+xIF6DqBQyWbwO3gduAmKjQuj7QL/ETEzQmMptl7Q9NBAAAAABJRU5ErkJggg==",
|
|
11
|
-
double:
|
|
12
|
+
double:
|
|
13
|
+
"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAG0lEQVR4nGNgGD7gPxjgYkN4yOyBlcDp3GEBAB3sd4lPaQxDAAAAAElFTkSuQmCC",
|
|
12
14
|
ring: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAANElEQVR4nGNgGBTgPxjgEseUgQphyCD4qDL/kSX+Y9WApoWqEjgsx+lc3B7EHSS4A3EgAAC+cEu1JTNREQAAAABJRU5ErkJggg==",
|
|
13
|
-
doubleRing:
|
|
15
|
+
doubleRing:
|
|
16
|
+
"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIklEQVR4nGNgGD7gPxjgYkN4yGwGmBA6SV0JHJbjdO6wAADBMlep8zl7TAAAAABJRU5ErkJggg==",
|
|
14
17
|
up: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAMElEQVR4nGNgoCv4////f1zi2GT+/4ciTHE4RhdHIlDFUUhkcTQKQx9WBw8PCVoBAIcbOcf3xeeBAAAAAElFTkSuQmCC",
|
|
15
18
|
down: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALUlEQVR4nGNgoC/4/3+4SkBFUCkkNjKJIoMg0GRgGEMGgrC4CQSwuxanR2gEAO1/Ocfgp8uvAAAAAElFTkSuQmCC",
|
|
16
19
|
left: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAI0lEQVR4nGNgoCv4j0sch8RAiTP8RwPESOAwajDI4JKgGQAAKO05x7DqJxIAAAAASUVORK5CYII=",
|
|
17
|
-
right:
|
|
20
|
+
right:
|
|
21
|
+
"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIElEQVR4nGNgoDf4j1NiMMn8RwOEJYizZKDEcQc7bQAAS7w5x+ro2lsAAAAASUVORK5CYII=",
|
|
18
22
|
hold: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAR0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKl0Z0Lof7DKbgMhBpQCZzOxedBHEGCMxAJBTXhKGRAA9hFMQEANr7jHQU9fO0AAAAASUVORK5CYII=",
|
|
19
|
-
holdRing:
|
|
23
|
+
holdRing:
|
|
24
|
+
"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAQ0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKlMd2IVQNMaEAlcDoXnwdxBAnOQCQU1ISjEIvjsYhiAgAo9KdZzePY3AAAAABJRU5ErkJggg==",
|
|
20
25
|
blank: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC",
|
|
21
26
|
}
|
|
@@ -80,7 +80,8 @@ export function normalizeManifestActions(raw: unknown): DeclaredAction[] {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const WIDGET_SIZES: readonly DeclaredWidgetSize[] = ["XS", "XSM", "SM", "MD", "LG"]
|
|
83
|
-
const isWidgetSize = (value: unknown): value is DeclaredWidgetSize =>
|
|
83
|
+
const isWidgetSize = (value: unknown): value is DeclaredWidgetSize =>
|
|
84
|
+
(WIDGET_SIZES as readonly unknown[]).includes(value)
|
|
84
85
|
|
|
85
86
|
/**
|
|
86
87
|
* Normalize manifest widgets for installed and dev-sideloaded bundles: an
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Keep installed-app icons from exhausting the miniapp's 32 MiB JS heap.
|
|
2
|
+
* Icons are optional; clients already render a fallback when one is absent.
|
|
3
|
+
* Bound both individual icons and their total before JSON crosses the bridge.
|
|
4
|
+
*/
|
|
5
|
+
export function notificationAppPayload(
|
|
6
|
+
apps: Array<{packageName: string; appName: string; icon: string | null}>,
|
|
7
|
+
): Array<{packageName: string; appName: string; icon: string | null}> {
|
|
8
|
+
let remaining = 128 * 1024
|
|
9
|
+
return apps.map(({packageName, appName, icon}) => {
|
|
10
|
+
const size = icon?.length ?? 0
|
|
11
|
+
const keep = size <= 8 * 1024 && size <= remaining
|
|
12
|
+
if (keep) remaining -= size
|
|
13
|
+
return {packageName, appName, icon: keep ? icon : null}
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -82,8 +82,7 @@ export function selectSettingsBridgeKeys(requested: unknown): string[] {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
export type SettingsSetValidation =
|
|
85
|
-
|
|
86
|
-
| {ok: false; code: "INVALID_ARGUMENT" | "NOT_PERMITTED"; message: string}
|
|
85
|
+
{ok: true; key: string; value: unknown} | {ok: false; code: "INVALID_ARGUMENT" | "NOT_PERMITTED"; message: string}
|
|
87
86
|
|
|
88
87
|
/** A SETTINGS_SET payload: a writable key and a JSON value (undefined is not a value). */
|
|
89
88
|
export function validateSettingsSet(payload: Record<string, unknown>): SettingsSetValidation {
|
|
@@ -44,8 +44,5 @@ export const isGatedByDevTools = (packageName: string, devToolsEnabled: boolean)
|
|
|
44
44
|
export const PAIRED_GLASSES_PACKAGES: ReadonlySet<string> = new Set(["com.glassly.store"])
|
|
45
45
|
|
|
46
46
|
/** True when the app waits on a pairing that hasn't happened and dev tools are off. */
|
|
47
|
-
export const isGatedUntilPaired = (
|
|
48
|
-
packageName
|
|
49
|
-
devToolsEnabled: boolean,
|
|
50
|
-
hasPairedGlasses: boolean,
|
|
51
|
-
): boolean => !devToolsEnabled && !hasPairedGlasses && PAIRED_GLASSES_PACKAGES.has(packageName)
|
|
47
|
+
export const isGatedUntilPaired = (packageName: string, devToolsEnabled: boolean, hasPairedGlasses: boolean): boolean =>
|
|
48
|
+
!devToolsEnabled && !hasPairedGlasses && PAIRED_GLASSES_PACKAGES.has(packageName)
|
|
@@ -29,13 +29,7 @@ export interface PhotoInfo {
|
|
|
29
29
|
|
|
30
30
|
// Sync state machine states
|
|
31
31
|
export type SyncState =
|
|
32
|
-
| "
|
|
33
|
-
| "requesting_hotspot"
|
|
34
|
-
| "connecting_wifi"
|
|
35
|
-
| "syncing"
|
|
36
|
-
| "complete"
|
|
37
|
-
| "error"
|
|
38
|
-
| "cancelled"
|
|
32
|
+
"idle" | "requesting_hotspot" | "connecting_wifi" | "syncing" | "complete" | "error" | "cancelled"
|
|
39
33
|
|
|
40
34
|
export interface HotspotInfo {
|
|
41
35
|
ssid: string
|
package/src/stores/settings.ts
CHANGED
|
@@ -333,7 +333,7 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
333
333
|
saveOnServer: false,
|
|
334
334
|
persist: true,
|
|
335
335
|
},
|
|
336
|
-
// User-supplied AI/voice provider keys (Settings > API Keys). Not consumed
|
|
336
|
+
// User-supplied AI/voice provider keys (Settings > Privacy > API Keys). Not consumed
|
|
337
337
|
// by the app itself — they exist so miniapps declaring the API_KEYS manifest
|
|
338
338
|
// permission can read them via session.keys.get() (see
|
|
339
339
|
// MINIAPP_READABLE_API_KEYS in LocalMiniappRuntime; mapbox is also readable
|
|
@@ -128,7 +128,7 @@ export function compileSvgPath(d: string): {commands: number[]; edges: number} {
|
|
|
128
128
|
curve(a, depth + 1)
|
|
129
129
|
curve(b, depth + 1)
|
|
130
130
|
}
|
|
131
|
-
for (let i = 0; i < commands.length;
|
|
131
|
+
for (let i = 0; i < commands.length;) {
|
|
132
132
|
const op = commands[i++],
|
|
133
133
|
pairs = op === 4 ? 0 : op === 3 ? 3 : op === 2 ? 2 : 1
|
|
134
134
|
if (++count > 1024) throw new Error("SVG path exceeds 1024 commands")
|
|
@@ -66,9 +66,7 @@ export function searchMemoryEntries<T extends MemorySearchableEntry>(
|
|
|
66
66
|
const windowCount = Math.max(0, hi - lo)
|
|
67
67
|
|
|
68
68
|
const needle = q.contains?.trim().toLowerCase() || null
|
|
69
|
-
const termWords = (q.terms ?? [])
|
|
70
|
-
.map((t) => tokenize(t))
|
|
71
|
-
.filter((words) => words.length > 0)
|
|
69
|
+
const termWords = (q.terms ?? []).map((t) => tokenize(t)).filter((words) => words.length > 0)
|
|
72
70
|
|
|
73
71
|
const picked: T[] = []
|
|
74
72
|
for (let i = hi - 1; i >= lo && picked.length < q.limit; i--) {
|
|
@@ -154,11 +152,23 @@ export function editDistanceAtMost(a: string, b: string, max: number): boolean {
|
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
const SOUNDEX_CODES: Record<string, string> = {
|
|
157
|
-
b: "1",
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
b: "1",
|
|
156
|
+
f: "1",
|
|
157
|
+
p: "1",
|
|
158
|
+
v: "1",
|
|
159
|
+
c: "2",
|
|
160
|
+
g: "2",
|
|
161
|
+
j: "2",
|
|
162
|
+
k: "2",
|
|
163
|
+
q: "2",
|
|
164
|
+
s: "2",
|
|
165
|
+
x: "2",
|
|
166
|
+
z: "2",
|
|
167
|
+
d: "3",
|
|
168
|
+
t: "3",
|
|
160
169
|
l: "4",
|
|
161
|
-
m: "5",
|
|
170
|
+
m: "5",
|
|
171
|
+
n: "5",
|
|
162
172
|
r: "6",
|
|
163
173
|
}
|
|
164
174
|
|