@glassly/engine 0.3.3-beta.639 → 0.3.3-beta.656
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/facades/glasses.d.ts +1 -0
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +1 -0
- package/build/facades/glasses.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 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/services/AiTierResolution.d.ts.map +1 -1
- package/build/services/AiTierResolution.js +11 -3
- package/build/services/AiTierResolution.js.map +1 -1
- package/build/services/GestureDotsService.d.ts.map +1 -1
- package/build/services/GestureDotsService.js +15 -6
- package/build/services/GestureDotsService.js.map +1 -1
- package/build/services/gestureDotGlyphs.d.ts +1 -1
- package/build/services/gestureDotGlyphs.d.ts.map +1 -1
- package/build/services/gestureDotGlyphs.js +1 -0
- package/build/services/gestureDotGlyphs.js.map +1 -1
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +1 -0
- package/build/stores/glasses.js.map +1 -1
- package/build/types/capabilities/even-realities-g2.js +1 -1
- package/build/types/capabilities/even-realities-g2.js.map +1 -1
- package/build/types/capabilities/mentra-display.js +1 -1
- package/build/types/capabilities/mentra-display.js.map +1 -1
- package/build/types/capabilities/rayneo-io.js +1 -1
- package/build/types/capabilities/rayneo-io.js.map +1 -1
- package/build/utils/timers/index.d.ts +1 -2
- package/build/utils/timers/index.d.ts.map +1 -1
- package/build/utils/timers/index.js +1 -2
- package/build/utils/timers/index.js.map +1 -1
- package/build/utils/timers/timers.d.ts +3 -5
- package/build/utils/timers/timers.d.ts.map +1 -1
- package/build/utils/timers/timers.js +78 -128
- package/build/utils/timers/timers.js.map +1 -1
- package/package.json +8 -8
- package/src/facades/glasses.ts +1 -0
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/index.ts +1 -1
- package/src/services/AiTierResolution.ts +12 -3
- package/src/services/GestureDotsService.ts +16 -6
- package/src/services/gestureDotGlyphs.ts +2 -1
- package/src/stores/glasses.ts +1 -0
- package/src/types/capabilities/even-realities-g2.ts +1 -1
- package/src/types/capabilities/mentra-display.ts +1 -1
- package/src/types/capabilities/rayneo-io.ts +1 -1
- package/src/utils/timers/index.ts +1 -2
- package/src/utils/timers/timers.ts +82 -157
package/src/index.ts
CHANGED
|
@@ -201,7 +201,7 @@ export {
|
|
|
201
201
|
type DevManifest,
|
|
202
202
|
} from "./utils/devMiniappLaunch"
|
|
203
203
|
export {HardwareCompatibility, type CompatibilityResult} from "./utils/hardware"
|
|
204
|
-
export {BgTimer
|
|
204
|
+
export {BgTimer} from "./utils/timers"
|
|
205
205
|
// Meta Neural Band: the account sign-in a claim needs (the WebView lives in the host).
|
|
206
206
|
export {
|
|
207
207
|
MetaAuthError,
|
|
@@ -42,7 +42,7 @@ export const TIER_MODEL_OPTIONS: Record<AiTier, TierModelOption[]> = {
|
|
|
42
42
|
],
|
|
43
43
|
frontier: [
|
|
44
44
|
{provider: "anthropic", model: "claude-sonnet-5", label: "Claude Sonnet 5"},
|
|
45
|
-
{provider: "gemini", model: "gemini-3.
|
|
45
|
+
{provider: "gemini", model: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro"},
|
|
46
46
|
{provider: "openai", model: "gpt-5.1", label: "GPT-5.1"},
|
|
47
47
|
],
|
|
48
48
|
}
|
|
@@ -60,6 +60,14 @@ export interface ResolvedTierModel {
|
|
|
60
60
|
model?: string
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Stored dropdown picks for model ids the provider never served, mapped to the
|
|
65
|
+
* curated replacement. gemini-3.5-pro 404s on generateContent.
|
|
66
|
+
*/
|
|
67
|
+
const RETIRED_MODELS: Record<string, string> = {
|
|
68
|
+
"gemini-3.5-pro": "gemini-3.1-pro-preview",
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
/** Coerce an untrusted wire value into a tier; anything else is "balanced". */
|
|
64
72
|
export function normalizeAiTier(value: unknown): AiTier {
|
|
65
73
|
return value === "quick" || value === "frontier" ? value : "balanced"
|
|
@@ -71,8 +79,9 @@ export function parseTierSetting(value: unknown): {provider: AiTierProvider; mod
|
|
|
71
79
|
const sep = value.indexOf(":")
|
|
72
80
|
if (sep <= 0) return null
|
|
73
81
|
const provider = value.slice(0, sep)
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
82
|
+
const stored = value.slice(sep + 1).trim()
|
|
83
|
+
if (!stored) return null
|
|
84
|
+
const model = RETIRED_MODELS[stored] ?? stored
|
|
76
85
|
if (provider !== "anthropic" && provider !== "gemini" && provider !== "openai") return null
|
|
77
86
|
return {provider, model}
|
|
78
87
|
}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* (cleared after a short pulse), a bullseye for a recognized long press.
|
|
6
6
|
* Controllers that report press edges (touch_down … tap_end) show the press
|
|
7
7
|
* itself instead: a dot while pressed, the bullseye once held, cleared at
|
|
8
|
-
* release. The Neural Band's middle finger (index 1) draws the same shapes
|
|
8
|
+
* release. The Neural Band's middle finger (index 1) draws the same shapes
|
|
9
|
+
* hollow: a ring for its tap, the bullseye without its center for its hold. Extracted from
|
|
9
10
|
* the CFW dashboard service; it renders through
|
|
10
11
|
* the ordinary scene pipeline, so it works on any positioning device (stock
|
|
11
12
|
* G2 included), and is gated by the gesture_dots debug setting.
|
|
@@ -41,7 +42,16 @@ const FLASH_GLYPHS: Record<string, GestureDotGlyph> = {
|
|
|
41
42
|
swipe_right: "right",
|
|
42
43
|
}
|
|
43
44
|
/** The band's middle finger draws the filled shapes hollow. */
|
|
44
|
-
const MIDDLE_FINGER_GLYPHS: Partial<Record<GestureDotGlyph, GestureDotGlyph>> = {
|
|
45
|
+
const MIDDLE_FINGER_GLYPHS: Partial<Record<GestureDotGlyph, GestureDotGlyph>> = {
|
|
46
|
+
dot: "ring",
|
|
47
|
+
double: "doubleRing",
|
|
48
|
+
hold: "holdRing",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** `glyph` as `finger` draws it: the middle finger's shapes are hollow. */
|
|
52
|
+
function fingerGlyph(glyph: GestureDotGlyph, finger: number): GestureDotGlyph {
|
|
53
|
+
return finger === 1 ? (MIDDLE_FINGER_GLYPHS[glyph] ?? glyph) : glyph
|
|
54
|
+
}
|
|
45
55
|
|
|
46
56
|
class GestureDotsService {
|
|
47
57
|
private started = false
|
|
@@ -135,12 +145,12 @@ class GestureDotsService {
|
|
|
135
145
|
if (press) {
|
|
136
146
|
// Both reports describe one press: after touch_down, tap_start means it is held.
|
|
137
147
|
if (gestureName === "touch_down") press.raw = true
|
|
138
|
-
else if (press.raw) press.glyph = "hold"
|
|
148
|
+
else if (press.raw) press.glyph = fingerGlyph("hold", finger)
|
|
139
149
|
this.render()
|
|
140
150
|
return
|
|
141
151
|
}
|
|
142
152
|
this.clearFlash()
|
|
143
|
-
this.presses.set(finger, {raw: gestureName === "touch_down", glyph:
|
|
153
|
+
this.presses.set(finger, {raw: gestureName === "touch_down", glyph: fingerGlyph("dot", finger)})
|
|
144
154
|
this.render()
|
|
145
155
|
return
|
|
146
156
|
}
|
|
@@ -152,14 +162,14 @@ class GestureDotsService {
|
|
|
152
162
|
return
|
|
153
163
|
}
|
|
154
164
|
const shape = FLASH_GLYPHS[gestureName]
|
|
155
|
-
const glyph = shape
|
|
165
|
+
const glyph = shape ? fingerGlyph(shape, finger) : shape
|
|
156
166
|
// The press already showed its own tap and hold; the device's report of
|
|
157
167
|
// them follows after its double-tap window, often after release.
|
|
158
168
|
const shownByPress = gestureName === "single_tap" || gestureName === "long_press"
|
|
159
169
|
if (press?.raw && (!glyph || shownByPress)) {
|
|
160
170
|
// Pinch-and-turn reports do not release a finger. A recognized hold
|
|
161
171
|
// stays visible until tap_end instead of expiring halfway through it.
|
|
162
|
-
if (gestureName === "long_press") press.glyph = "hold"
|
|
172
|
+
if (gestureName === "long_press") press.glyph = fingerGlyph("hold", finger)
|
|
163
173
|
this.render()
|
|
164
174
|
return
|
|
165
175
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export const GESTURE_DOT_GLYPH_SIZE = 24
|
|
6
6
|
|
|
7
|
-
export type GestureDotGlyph = "dot" | "double" | "ring" | "doubleRing" | "up" | "down" | "left" | "right" | "hold" | "blank"
|
|
7
|
+
export type GestureDotGlyph = "dot" | "double" | "ring" | "doubleRing" | "up" | "down" | "left" | "right" | "hold" | "holdRing" | "blank"
|
|
8
8
|
|
|
9
9
|
export const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string> = {
|
|
10
10
|
dot: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALklEQVR4nM2QsQ0AAAjC/P/pmrhqZ+xIF6DqBQyWbwO3gduAmKjQuj7QL/ETEzQmMptl7Q9NBAAAAABJRU5ErkJggg==",
|
|
@@ -16,5 +16,6 @@ export const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string> = {
|
|
|
16
16
|
left: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAI0lEQVR4nGNgoCv4j0sch8RAiTP8RwPESOAwajDI4JKgGQAAKO05x7DqJxIAAAAASUVORK5CYII=",
|
|
17
17
|
right: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIElEQVR4nGNgoDf4j1NiMMn8RwOEJYizZKDEcQc7bQAAS7w5x+ro2lsAAAAASUVORK5CYII=",
|
|
18
18
|
hold: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAR0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKl0Z0Lof7DKbgMhBpQCZzOxedBHEGCMxAJBTXhKGRAA9hFMQEANr7jHQU9fO0AAAAASUVORK5CYII=",
|
|
19
|
+
holdRing: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAQ0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKlMd2IVQNMaEAlcDoXnwdxBAnOQCQU1ISjEIvjsYhiAgAo9KdZzePY3AAAAABJRU5ErkJggg==",
|
|
19
20
|
blank: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC",
|
|
20
21
|
}
|
package/src/stores/glasses.ts
CHANGED
|
@@ -42,7 +42,7 @@ export const evenRealitiesG2: Capabilities = {
|
|
|
42
42
|
// envelope). Pathological sizes needing more than the 4-container pool are
|
|
43
43
|
// dropped SGC-side with a log.
|
|
44
44
|
shapes: ["rect"], // bordered empty container ≈ rect
|
|
45
|
-
intensityLevels:
|
|
45
|
+
intensityLevels: 16,
|
|
46
46
|
partialUpdate: true,
|
|
47
47
|
},
|
|
48
48
|
|
|
@@ -39,7 +39,7 @@ export const mentraDisplay: Capabilities = {
|
|
|
39
39
|
maxImageElements: 4, // firmware BITMAP pool ids 10-13
|
|
40
40
|
maxImagePx: {width: 200, height: 200}, // CANVAS_IMAGE_MAX_I1_BYTES / NAV_IMAGE_MAX_W/H
|
|
41
41
|
shapes: ["rect"], // bordered empty TEXTBOX ≈ rect (no shape primitive)
|
|
42
|
-
intensityLevels:
|
|
42
|
+
intensityLevels: 16,
|
|
43
43
|
partialUpdate: true,
|
|
44
44
|
},
|
|
45
45
|
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export {BgTimer, throttle, debounce}
|
|
1
|
+
export {BgTimer} from "./timers"
|
|
@@ -1,203 +1,128 @@
|
|
|
1
|
-
// BgTimer
|
|
1
|
+
// BgTimer: every engine timer (miniapp liveness watchdog, display expiries,
|
|
2
|
+
// boot windows, token refresh) goes through here. Android pauses plain JS
|
|
3
|
+
// timers while the app is backgrounded, so on a device these run on the
|
|
4
|
+
// native react-native-nitro-bg-timer instead. iOS needs that package at
|
|
5
|
+
// >= 0.2.0: earlier versions cleared each timer right after scheduling it
|
|
6
|
+
// (https://github.com/tconns/react-native-nitro-bg-timer/issues/2).
|
|
2
7
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// background when the native implementation (react-native-nitro-bg-timer)
|
|
8
|
-
// is active.
|
|
8
|
+
// Dev and release behave the same; there is no env switch. A missing native
|
|
9
|
+
// module falls back to JS timers so the foreground keeps working, and says so
|
|
10
|
+
// once, loudly: a quiet fallback already cost a day of phantom "zombie
|
|
11
|
+
// miniapp" bugs (OS-1790). Never downgrade that report to a warning.
|
|
9
12
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// - iOS: never, dev or prod — the package is disabled pending
|
|
21
|
-
// https://github.com/tconns/react-native-nitro-bg-timer/issues/2. iOS
|
|
22
|
-
// suspends the whole process in background anyway, so background timing
|
|
23
|
-
// there is handled by native per-device queues, not JS timers.
|
|
24
|
-
//
|
|
25
|
-
// react-native is loaded lazily, not imported. Every engine service runs its
|
|
26
|
-
// timers through this module, and the engine's bun test suites load those
|
|
27
|
-
// services in a plain JS runtime that cannot parse react-native's Flow
|
|
28
|
-
// source. A static import would force every such suite to mock this module;
|
|
29
|
-
// with the lazy load, a runtime without react-native simply gets the JS
|
|
30
|
-
// timers, which is the correct answer there anyway.
|
|
13
|
+
// react-native and the nitro packages are require()d lazily. The engine's bun
|
|
14
|
+
// suites run services in a plain JS runtime that cannot parse react-native;
|
|
15
|
+
// there the native lookup finds no platform and JS timers are the right answer.
|
|
16
|
+
|
|
17
|
+
type TimerApi = {
|
|
18
|
+
setTimeout(callback: () => void, delay: number): number
|
|
19
|
+
clearTimeout(id: number): void
|
|
20
|
+
setInterval(callback: () => void, delay: number): number
|
|
21
|
+
clearInterval(id: number): void
|
|
22
|
+
}
|
|
31
23
|
|
|
32
24
|
type ReactNativeSubset = {
|
|
33
25
|
Platform: {OS: string}
|
|
34
|
-
Alert?: {alert
|
|
26
|
+
Alert?: {alert(title: string, message?: string): void}
|
|
35
27
|
}
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
const TIMER_METHODS = ["setTimeout", "clearTimeout", "setInterval", "clearInterval"] as const
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
reactNative = require("react-native") as ReactNativeSubset
|
|
45
|
-
} catch {
|
|
46
|
-
reactNative = null
|
|
47
|
-
}
|
|
48
|
-
return reactNative
|
|
31
|
+
const jsTimers: TimerApi = {
|
|
32
|
+
setTimeout: (callback, delay) => setTimeout(callback, delay) as unknown as number,
|
|
33
|
+
clearTimeout: (id) => clearTimeout(id),
|
|
34
|
+
setInterval: (callback, delay) => setInterval(callback, delay) as unknown as number,
|
|
35
|
+
clearInterval: (id) => clearInterval(id),
|
|
49
36
|
}
|
|
50
37
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
let reactNative: ReactNativeSubset | null | undefined
|
|
39
|
+
// undefined = not looked up yet, null = unavailable (JS timers from here on).
|
|
40
|
+
let nativeTimers: TimerApi | null | undefined
|
|
41
|
+
let reported = false
|
|
54
42
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
function loadReactNative(): ReactNativeSubset | null {
|
|
44
|
+
if (reactNative === undefined) {
|
|
45
|
+
try {
|
|
46
|
+
reactNative = require("react-native") as ReactNativeSubset
|
|
47
|
+
} catch {
|
|
48
|
+
reactNative = null
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return reactNative
|
|
60
52
|
}
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
* The native background timer is unavailable — say so ONCE, loudly, with the
|
|
68
|
-
* remediation. The JS-timer fallback keeps foreground behavior working, but
|
|
69
|
-
* everything timing-driven freezes while the app is backgrounded, which
|
|
70
|
-
* presents as phantom miniapp bugs (frozen captions, missed wake words,
|
|
71
|
-
* watchdog kills on resume). A quiet warning here has already cost a full
|
|
72
|
-
* debugging day; never downgrade this to console.warn.
|
|
73
|
-
*/
|
|
74
|
-
function failUnavailable(reason: string) {
|
|
75
|
-
if (failedLoud) {
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
failedLoud = true
|
|
54
|
+
function reportUnavailable(reason: string): void {
|
|
55
|
+
if (reported) return
|
|
56
|
+
reported = true
|
|
57
|
+
const rn = loadReactNative()
|
|
58
|
+
const platform = rn?.Platform.OS === "ios" ? "ios" : "android"
|
|
79
59
|
const message =
|
|
80
60
|
`BgTimer: native background timer unavailable (${reason}). ` +
|
|
81
|
-
|
|
61
|
+
`Backgrounded behavior IS BROKEN until you rebuild the app: run \`bun ${platform}\`. ` +
|
|
82
62
|
"Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded."
|
|
83
63
|
console.error(message)
|
|
84
|
-
if (
|
|
85
|
-
// A stale dev client may
|
|
86
|
-
//
|
|
87
|
-
// is the actionable one: it names the fix.
|
|
64
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
65
|
+
// A stale dev client may also red-box inside the library itself; this
|
|
66
|
+
// alert is the one that names the fix.
|
|
88
67
|
try {
|
|
89
|
-
|
|
68
|
+
rn?.Alert?.alert("Background timers unavailable", message)
|
|
90
69
|
} catch {
|
|
91
|
-
|
|
70
|
+
// Headless runtime: the console.error stands.
|
|
92
71
|
}
|
|
93
72
|
}
|
|
94
73
|
}
|
|
95
74
|
|
|
96
|
-
function
|
|
97
|
-
if (
|
|
75
|
+
function loadNativeTimers(): TimerApi | null {
|
|
76
|
+
if (nativeTimers !== undefined) return nativeTimers
|
|
77
|
+
const platform = loadReactNative()?.Platform.OS
|
|
78
|
+
if (platform !== "android" && platform !== "ios") {
|
|
79
|
+
nativeTimers = null
|
|
98
80
|
return null
|
|
99
81
|
}
|
|
100
|
-
|
|
101
|
-
if (nitroTimer !== undefined) {
|
|
102
|
-
return nitroTimer
|
|
103
|
-
}
|
|
104
|
-
|
|
105
82
|
try {
|
|
106
83
|
const {isRuntimeAlive} = require("react-native-nitro-modules") as {isRuntimeAlive?: () => boolean}
|
|
107
|
-
if (typeof isRuntimeAlive === "function" && !isRuntimeAlive())
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
84
|
+
if (typeof isRuntimeAlive === "function" && !isRuntimeAlive()) throw new Error("nitro runtime is not alive")
|
|
85
|
+
const {BackgroundTimer} = require("react-native-nitro-bg-timer") as {BackgroundTimer?: Partial<TimerApi>}
|
|
86
|
+
for (const method of TIMER_METHODS) {
|
|
87
|
+
if (typeof BackgroundTimer?.[method] !== "function") throw new Error(`BackgroundTimer.${method} missing`)
|
|
111
88
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
typeof BackgroundTimer.setTimeout === "function" &&
|
|
117
|
-
typeof BackgroundTimer.setInterval === "function" &&
|
|
118
|
-
typeof BackgroundTimer.clearTimeout === "function" &&
|
|
119
|
-
typeof BackgroundTimer.clearInterval === "function"
|
|
120
|
-
? BackgroundTimer
|
|
121
|
-
: null
|
|
122
|
-
} catch {
|
|
123
|
-
nitroTimer = null
|
|
124
|
-
nitroDisabled = true
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!nitroTimer) {
|
|
128
|
-
failUnavailable("react-native-nitro-bg-timer failed to load")
|
|
89
|
+
nativeTimers = BackgroundTimer as TimerApi
|
|
90
|
+
} catch (error) {
|
|
91
|
+
nativeTimers = null
|
|
92
|
+
reportUnavailable(error instanceof Error ? error.message : String(error))
|
|
129
93
|
}
|
|
130
|
-
return
|
|
94
|
+
return nativeTimers
|
|
131
95
|
}
|
|
132
96
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
97
|
+
// A native call that throws mid-session is new information: drop to JS timers
|
|
98
|
+
// and announce again.
|
|
99
|
+
function call<T>(run: (timers: TimerApi) => T): T {
|
|
100
|
+
const native = loadNativeTimers()
|
|
101
|
+
if (!native) return run(jsTimers)
|
|
138
102
|
try {
|
|
139
|
-
return run(
|
|
103
|
+
return run(native)
|
|
140
104
|
} catch (error) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return fallback()
|
|
105
|
+
nativeTimers = null
|
|
106
|
+
reported = false
|
|
107
|
+
reportUnavailable(`native timer call threw: ${String(error)}`)
|
|
108
|
+
return run(jsTimers)
|
|
146
109
|
}
|
|
147
110
|
}
|
|
148
111
|
|
|
149
112
|
export class BgTimer {
|
|
150
|
-
static setInterval(callback: () => void, delay: number): number {
|
|
151
|
-
return withNitro(
|
|
152
|
-
(api) => api.setInterval(callback, delay),
|
|
153
|
-
() => setInterval(callback, delay) as unknown as number,
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
static clearInterval(intervalId: number): void {
|
|
158
|
-
withNitro(
|
|
159
|
-
(api) => api.clearInterval(intervalId),
|
|
160
|
-
() => clearInterval(intervalId),
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
113
|
static setTimeout(callback: () => void, delay: number): number {
|
|
165
|
-
return
|
|
166
|
-
(api) => api.setTimeout(callback, delay),
|
|
167
|
-
() => setTimeout(callback, delay) as unknown as number,
|
|
168
|
-
)
|
|
114
|
+
return call((timers) => timers.setTimeout(callback, delay))
|
|
169
115
|
}
|
|
170
116
|
|
|
171
|
-
static clearTimeout(
|
|
172
|
-
|
|
173
|
-
(api) => api.clearTimeout(timeoutId),
|
|
174
|
-
() => clearTimeout(timeoutId),
|
|
175
|
-
)
|
|
117
|
+
static clearTimeout(id: number): void {
|
|
118
|
+
call((timers) => timers.clearTimeout(id))
|
|
176
119
|
}
|
|
177
|
-
}
|
|
178
120
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return (...args: Parameters<T>) => {
|
|
183
|
-
const now = Date.now()
|
|
184
|
-
if (now - lastCalled >= ms) {
|
|
185
|
-
lastCalled = now
|
|
186
|
-
fn(...args)
|
|
187
|
-
}
|
|
121
|
+
static setInterval(callback: () => void, delay: number): number {
|
|
122
|
+
return call((timers) => timers.setInterval(callback, delay))
|
|
188
123
|
}
|
|
189
|
-
}
|
|
190
124
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return (...args: Parameters<T>) => {
|
|
195
|
-
if (timeoutId) {
|
|
196
|
-
BgTimer.clearTimeout(timeoutId)
|
|
197
|
-
}
|
|
198
|
-
timeoutId = BgTimer.setTimeout(() => {
|
|
199
|
-
fn(...args)
|
|
200
|
-
timeoutId = null
|
|
201
|
-
}, ms)
|
|
125
|
+
static clearInterval(id: number): void {
|
|
126
|
+
call((timers) => timers.clearInterval(id))
|
|
202
127
|
}
|
|
203
128
|
}
|