@glassly/engine 0.3.3-dev.642 → 0.3.3-dev.645
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/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/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/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 +7 -7
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/index.ts +1 -1
- package/src/services/GestureDotsService.ts +16 -6
- package/src/services/gestureDotGlyphs.ts +2 -1
- package/src/utils/timers/index.ts +1 -2
- package/src/utils/timers/timers.ts +82 -157
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export const ENGINE_RELEASE_METADATA = Object.freeze({
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"familyBaseVersion": "0.3.3",
|
|
4
|
-
"releaseIdentity": "0.3.3-dev.
|
|
5
|
-
"releaseSetId": "glassly-0.3.3-dev.
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"releaseIdentity": "0.3.3-dev.645",
|
|
5
|
+
"releaseSetId": "glassly-0.3.3-dev.645",
|
|
6
|
+
"sourceCommit": "d448896b180f4eb054a597d2c460d6eae8841a64",
|
|
7
7
|
"otaManifestUrl": null,
|
|
8
8
|
"otaManifestSha256": null
|
|
9
9
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.3\",\n \"releaseIdentity\": \"0.3.3-dev.
|
|
1
|
+
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.3\",\n \"releaseIdentity\": \"0.3.3-dev.645\",\n \"releaseSetId\": \"glassly-0.3.3-dev.645\",\n \"sourceCommit\": \"d448896b180f4eb054a597d2c460d6eae8841a64\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export { WebSocketStatus } from "./stores/connection";
|
|
|
48
48
|
export { DUMMY_APPLET, saveAppsOrder, getAppsOrder, sortAppsByPackageNamePriority, saveLastOpenTime, getLastOpenTime, sortAppsByLastOpenTime, useApps, useStart, useStop, useSetForeground, useClearForeground, useRefresh, useStopAll, useInstall, useUninstall, useActiveApps, useRunningAlwaysOnApps, useActiveBackgroundApps, useBackgroundApps, useActiveForegroundApp, useForegroundApp, useActiveBackgroundAppsCount, useLocalMiniApps, type StartOptions, type OrderMap, } from "./stores/apps";
|
|
49
49
|
export { decideDevLaunchRoute, type DecideDevLaunchOptions, type DevLaunchResult, type DevManifest, } from "./utils/devMiniappLaunch";
|
|
50
50
|
export { HardwareCompatibility, type CompatibilityResult } from "./utils/hardware";
|
|
51
|
-
export { BgTimer
|
|
51
|
+
export { BgTimer } from "./utils/timers";
|
|
52
52
|
export { MetaAuthError, authEntryUrl, callbackMatches, callbackQuery, decryptBlob, isLoginCallback, login, tokensQuery, type MetaSession, type MetaSsoTokens, } from "./services/neuralBand/MetaAuth";
|
|
53
53
|
export type { NeuralBandClaimStatus, NeuralBandHandwritingStatus } from "./services/neuralBand/NeuralBandInput";
|
|
54
54
|
export { HardwareType, HardwareRequirementLevel, DeviceTypes, ControllerTypes, HARDWARE_CAPABILITIES, getModelCapabilities, simulatedGlasses, evenRealitiesG1, evenRealitiesG2, mentraLive, nimo, rayneoIO, vuzixZ100, mentraDisplay, } from "./types";
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -47,7 +47,7 @@ export { DUMMY_APPLET, saveAppsOrder, getAppsOrder, sortAppsByPackageNamePriorit
|
|
|
47
47
|
// Pure dev-miniapp launch-route decision (registration itself is internal).
|
|
48
48
|
export { decideDevLaunchRoute, } from "./utils/devMiniappLaunch";
|
|
49
49
|
export { HardwareCompatibility } from "./utils/hardware";
|
|
50
|
-
export { BgTimer
|
|
50
|
+
export { BgTimer } from "./utils/timers";
|
|
51
51
|
// Meta Neural Band: the account sign-in a claim needs (the WebView lives in the host).
|
|
52
52
|
export { MetaAuthError, authEntryUrl, callbackMatches, callbackQuery, decryptBlob, isLoginCallback, login, tokensQuery, } from "./services/neuralBand/MetaAuth";
|
|
53
53
|
// Hardware types and capability profiles.
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `@glassly/engine` — the OEM-facing main entry.\n *\n * The `engine` namespace (configure/start/stop + typed domain facades), the\n * public contract/read-model types, and the pure helpers host UI legitimately\n * renders with (decision functions, sort/order helpers, policy constants,\n * capability tables, timers). Judgment rule: read models, commands, pure\n * functions and types belong here; anything that mutates runtime state or\n * exposes a raw store/service remains private to the Glassly host.\n * See cloud/docs/issues/020-glasses-status-boundary/integration-review.md §D.\n */\n\n// The namespaced OEM-facing engine API (the \"(A) host API\"). See ./engine.\nexport {engine} from \"./engine\"\nexport type {\n ReportAttachmentInput,\n ReportContext,\n ReportDetails,\n ReportStatus,\n ReportTrigger,\n ReportSubmitResult,\n EngineSubmitReportInput,\n} from \"./facades/reports\"\nexport type {IslandNotification, IslandNotificationKind} from \"./facades/notifications\"\nexport type {PresentationOwner} from \"./services/notifications/notificationPolicy\"\nexport {DEFAULT_HIDDEN_PACKAGES, isGatedByDevTools, isSystemMiniapp} from \"./stores/appVisibility\"\nexport type {WifiSearchResult} from \"./facades/glassesWifi\"\nexport type {IdentitySnapshot} from \"./services/PairingIdentity\"\nexport type {DisplayMirrorEvent} from \"./facades/displayMirror\"\nexport type {\n IslandConfigureOptions,\n IslandAuth,\n IslandConfigValues,\n IslandAnalytics,\n IslandUiSeams,\n ScanQrOptions,\n ScanQrResult,\n SubjectTokenType,\n} from \"./runtime/bootstrap\"\n\n// Settings contract: the typed key registry (schema descriptors — the same\n// surface engine.settings.descriptor()/keys() reads), the per-key React hook\n// (the hook layer, same precedent as the apps hooks below), and the pure\n// device-model key helpers. The raw useSettingsStore stays internal;\n// imperative access goes through engine.settings.\nexport {SETTINGS, useSetting, AI_DATA_CONSENT_VERSION} from \"./stores/settings\"\nexport {isCfwFirmwareVersion, isCustomDashboardEligible} from \"./services/pages/pageEligibility\"\nexport {getEffectiveCapabilities} from \"./services/effectiveCapabilities\"\n\n// AI tier registry: the curated per-tier model dropdown options and helpers\n// the Settings > AI Models screen renders. Resolution itself runs inside\n// LocalMiniappRuntime; the screen only reads/writes the ai_model_* settings.\nexport {AI_TIERS, TIER_MODEL_OPTIONS, parseTierSetting} from \"./services/AiTierResolution\"\nexport type {AiTier, AiTierProvider, TierModelOption} from \"./services/AiTierResolution\"\n\n// Shared user memory timeline (engine.memory / Settings > Memory). Entry and\n// session shapes are canonical in @glassly/miniapp (the session.memory\n// surface); the stats read model is engine-side.\nexport type {MemoryStats} from \"./services/MemoryStore\"\nexport type {SpeakerProfile} from \"./services/SpeakerProfileStore\"\nexport type {EnrollOutcome} from \"./facades/speakers\"\nexport {MENTRA_LIVE_SETTING_KEYS, getBluetoothSettingKeysForDevice} from \"./stores/bluetoothSettingKeys\"\n\n// Runtime-shared constants and contract DTOs.\nexport {ISLAND_SETTINGS_KEYS} from \"./runtime/config\"\nexport type {CloudClientStatusSnapshot, MiniappAuthToken, InteropAuditEvent, TtsSynthesisResult} from \"./runtime/config\"\n\n// Pure readiness predicates over glasses connection state.\nexport {\n isGlassesConnected,\n isGlassesReady,\n isGlassesLinkLayerBusy,\n waitForGlassesReady,\n type GlassesConnectionStatus,\n type WaitForGlassesReadyOptions,\n} from \"./services/GlassesReadiness\"\n// Pure connect/reconnect decision helpers (host UI renders the outcome).\nexport {\n decideReconnect,\n decideConnectButtonAction,\n type ReconnectDecision,\n type ReconnectDecisionInput,\n type ConnectButtonAction,\n} from \"./services/ConnectionCoordinator\"\n\n// OTA read-model types for host OTA UI (progress screen, error mapping,\n// progress section) — the check/install machinery itself is internal.\nexport type {\n VersionInfo,\n MtkPatch,\n BesFirmware,\n VersionJson,\n OtaCheckResult,\n OtaCheckCurrentGlassesResult,\n OtaCheckCurrentGlassesOptions,\n} from \"./services/OtaUpdateCheckService\"\n// OTA install policy (watchdog timings + failure copy) + display-state\n// derivation, consumed by the OTA screens and their tests.\nexport {\n MINIMUM_OTA_STATUS_BUILD,\n MAX_RETRIES,\n RETRY_INTERVAL_MS,\n PROGRESS_TIMEOUT_MS,\n DOWNLOAD_STUCK_TIMEOUT_MS,\n MTK_INSTALL_TIMEOUT_MS,\n GLOBAL_OTA_TIMEOUT_MS,\n PING_INTERVAL_MS,\n QUERY_REPLY_TIMEOUT_MS,\n BES_RESTART_TIMEOUT_MS,\n OtaProgressMessages,\n} from \"./services/otaInstallPolicy\"\nexport {deriveDisplayState} from \"./services/otaDisplayState\"\nexport type {DisplayState} from \"./services/otaDisplayState\"\nexport type {\n OtaProgress,\n OtaProgressStatus,\n OtaStatus,\n OtaUpdateInfo,\n ReleaseChangelog,\n OtaSnapshot,\n OtaInstallSnapshot,\n} from \"./facades/ota\"\nexport {\n beginOtaAutoChain,\n clearOtaAutoChainReconnectWait,\n isOtaAutoChainActive,\n otaAutoChainFingerprint,\n otaAutoChainReconnectWaitRemaining,\n stopOtaAutoChain,\n tryAdvanceOtaAutoChain,\n MAX_OTA_AUTO_CHAIN_PASSES,\n OTA_AUTO_CHAIN_RECONNECT_TIMEOUT_MS,\n} from \"./services/OtaAutoChain\"\nexport type {OtaAutoChainAdvanceResult} from \"./services/OtaAutoChain\"\nexport {\n BES_INSTALL_RESTART_MESSAGE,\n getOtaErrorMessage,\n shouldRequireGlassesRebootForBesFailure,\n shouldShowChangeWifiForOtaDownloadFailure,\n} from \"./services/OtaErrorMapping\"\n\n// Gallery read models: engine.gallery.onNotice payload types, the media\n// permission helper + display-name derivation host gallery UI uses, and the\n// glasses-camera DTO types (re-exported through the host @/types/asg shim).\nexport type {GalleryNotice, GalleryNoticeCode} from \"./services/asg/galleryNotices\"\nexport {MediaLibraryPermissions} from \"./utils/permissions/MediaLibraryPermissions\"\nexport {deriveGalleryDisplayName} from \"./utils/permissions/galleryDisplayName\"\nexport type {\n PhotoInfo,\n CaptureFile,\n CaptureGroup,\n GalleryResponse,\n ServerStatus,\n HealthResponse,\n GalleryEvent,\n} from \"./types/asg\"\n\n// Bluetooth SDK event types host UI subscribes to via engine facades (the\n// BluetoothSdk singleton passthrough itself is internal).\nexport type {PairFailureEvent, GlassesNotReadyEvent} from \"@glassly/bluetooth-sdk\"\n\n// Cloud connection status enum (read model; the connection store is internal).\nexport {WebSocketStatus} from \"./stores/connection\"\n\n// App-list hook layer + pure list helpers (the raw useAppStatusStore and\n// installAppStoreHooks wiring are internal).\nexport {\n DUMMY_APPLET,\n saveAppsOrder,\n getAppsOrder,\n sortAppsByPackageNamePriority,\n saveLastOpenTime,\n getLastOpenTime,\n sortAppsByLastOpenTime,\n useApps,\n useStart,\n useStop,\n useSetForeground,\n useClearForeground,\n useRefresh,\n useStopAll,\n useInstall,\n useUninstall,\n useActiveApps,\n useRunningAlwaysOnApps,\n useActiveBackgroundApps,\n useBackgroundApps,\n useActiveForegroundApp,\n useForegroundApp,\n useActiveBackgroundAppsCount,\n useLocalMiniApps,\n type StartOptions,\n type OrderMap,\n} from \"./stores/apps\"\n\n// Pure dev-miniapp launch-route decision (registration itself is internal).\nexport {\n decideDevLaunchRoute,\n type DecideDevLaunchOptions,\n type DevLaunchResult,\n type DevManifest,\n} from \"./utils/devMiniappLaunch\"\nexport {HardwareCompatibility, type CompatibilityResult} from \"./utils/hardware\"\nexport {BgTimer, throttle, debounce} from \"./utils/timers\"\n// Meta Neural Band: the account sign-in a claim needs (the WebView lives in the host).\nexport {\n MetaAuthError,\n authEntryUrl,\n callbackMatches,\n callbackQuery,\n decryptBlob,\n isLoginCallback,\n login,\n tokensQuery,\n type MetaSession,\n type MetaSsoTokens,\n} from \"./services/neuralBand/MetaAuth\"\nexport type {NeuralBandClaimStatus, NeuralBandHandwritingStatus} from \"./services/neuralBand/NeuralBandInput\"\n\n// Hardware types and capability profiles.\nexport {\n HardwareType,\n HardwareRequirementLevel,\n DeviceTypes,\n ControllerTypes,\n HARDWARE_CAPABILITIES,\n getModelCapabilities,\n simulatedGlasses,\n evenRealitiesG1,\n evenRealitiesG2,\n mentraLive,\n nimo,\n rayneoIO,\n vuzixZ100,\n mentraDisplay,\n} from \"./types\"\nexport type {\n HardwareRequirement,\n CameraCapabilities,\n DisplayCapabilities,\n MicrophoneCapabilities,\n SpeakerCapabilities,\n IMUCapabilities,\n ButtonCapabilities,\n LightCapabilities,\n PowerCapabilities,\n Capabilities,\n AppletType,\n AppPermissionType,\n AppletPermission,\n AppletInterface,\n ClientApp,\n} from \"./types\"\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `@glassly/engine` — the OEM-facing main entry.\n *\n * The `engine` namespace (configure/start/stop + typed domain facades), the\n * public contract/read-model types, and the pure helpers host UI legitimately\n * renders with (decision functions, sort/order helpers, policy constants,\n * capability tables, timers). Judgment rule: read models, commands, pure\n * functions and types belong here; anything that mutates runtime state or\n * exposes a raw store/service remains private to the Glassly host.\n * See cloud/docs/issues/020-glasses-status-boundary/integration-review.md §D.\n */\n\n// The namespaced OEM-facing engine API (the \"(A) host API\"). See ./engine.\nexport {engine} from \"./engine\"\nexport type {\n ReportAttachmentInput,\n ReportContext,\n ReportDetails,\n ReportStatus,\n ReportTrigger,\n ReportSubmitResult,\n EngineSubmitReportInput,\n} from \"./facades/reports\"\nexport type {IslandNotification, IslandNotificationKind} from \"./facades/notifications\"\nexport type {PresentationOwner} from \"./services/notifications/notificationPolicy\"\nexport {DEFAULT_HIDDEN_PACKAGES, isGatedByDevTools, isSystemMiniapp} from \"./stores/appVisibility\"\nexport type {WifiSearchResult} from \"./facades/glassesWifi\"\nexport type {IdentitySnapshot} from \"./services/PairingIdentity\"\nexport type {DisplayMirrorEvent} from \"./facades/displayMirror\"\nexport type {\n IslandConfigureOptions,\n IslandAuth,\n IslandConfigValues,\n IslandAnalytics,\n IslandUiSeams,\n ScanQrOptions,\n ScanQrResult,\n SubjectTokenType,\n} from \"./runtime/bootstrap\"\n\n// Settings contract: the typed key registry (schema descriptors — the same\n// surface engine.settings.descriptor()/keys() reads), the per-key React hook\n// (the hook layer, same precedent as the apps hooks below), and the pure\n// device-model key helpers. The raw useSettingsStore stays internal;\n// imperative access goes through engine.settings.\nexport {SETTINGS, useSetting, AI_DATA_CONSENT_VERSION} from \"./stores/settings\"\nexport {isCfwFirmwareVersion, isCustomDashboardEligible} from \"./services/pages/pageEligibility\"\nexport {getEffectiveCapabilities} from \"./services/effectiveCapabilities\"\n\n// AI tier registry: the curated per-tier model dropdown options and helpers\n// the Settings > AI Models screen renders. Resolution itself runs inside\n// LocalMiniappRuntime; the screen only reads/writes the ai_model_* settings.\nexport {AI_TIERS, TIER_MODEL_OPTIONS, parseTierSetting} from \"./services/AiTierResolution\"\nexport type {AiTier, AiTierProvider, TierModelOption} from \"./services/AiTierResolution\"\n\n// Shared user memory timeline (engine.memory / Settings > Memory). Entry and\n// session shapes are canonical in @glassly/miniapp (the session.memory\n// surface); the stats read model is engine-side.\nexport type {MemoryStats} from \"./services/MemoryStore\"\nexport type {SpeakerProfile} from \"./services/SpeakerProfileStore\"\nexport type {EnrollOutcome} from \"./facades/speakers\"\nexport {MENTRA_LIVE_SETTING_KEYS, getBluetoothSettingKeysForDevice} from \"./stores/bluetoothSettingKeys\"\n\n// Runtime-shared constants and contract DTOs.\nexport {ISLAND_SETTINGS_KEYS} from \"./runtime/config\"\nexport type {CloudClientStatusSnapshot, MiniappAuthToken, InteropAuditEvent, TtsSynthesisResult} from \"./runtime/config\"\n\n// Pure readiness predicates over glasses connection state.\nexport {\n isGlassesConnected,\n isGlassesReady,\n isGlassesLinkLayerBusy,\n waitForGlassesReady,\n type GlassesConnectionStatus,\n type WaitForGlassesReadyOptions,\n} from \"./services/GlassesReadiness\"\n// Pure connect/reconnect decision helpers (host UI renders the outcome).\nexport {\n decideReconnect,\n decideConnectButtonAction,\n type ReconnectDecision,\n type ReconnectDecisionInput,\n type ConnectButtonAction,\n} from \"./services/ConnectionCoordinator\"\n\n// OTA read-model types for host OTA UI (progress screen, error mapping,\n// progress section) — the check/install machinery itself is internal.\nexport type {\n VersionInfo,\n MtkPatch,\n BesFirmware,\n VersionJson,\n OtaCheckResult,\n OtaCheckCurrentGlassesResult,\n OtaCheckCurrentGlassesOptions,\n} from \"./services/OtaUpdateCheckService\"\n// OTA install policy (watchdog timings + failure copy) + display-state\n// derivation, consumed by the OTA screens and their tests.\nexport {\n MINIMUM_OTA_STATUS_BUILD,\n MAX_RETRIES,\n RETRY_INTERVAL_MS,\n PROGRESS_TIMEOUT_MS,\n DOWNLOAD_STUCK_TIMEOUT_MS,\n MTK_INSTALL_TIMEOUT_MS,\n GLOBAL_OTA_TIMEOUT_MS,\n PING_INTERVAL_MS,\n QUERY_REPLY_TIMEOUT_MS,\n BES_RESTART_TIMEOUT_MS,\n OtaProgressMessages,\n} from \"./services/otaInstallPolicy\"\nexport {deriveDisplayState} from \"./services/otaDisplayState\"\nexport type {DisplayState} from \"./services/otaDisplayState\"\nexport type {\n OtaProgress,\n OtaProgressStatus,\n OtaStatus,\n OtaUpdateInfo,\n ReleaseChangelog,\n OtaSnapshot,\n OtaInstallSnapshot,\n} from \"./facades/ota\"\nexport {\n beginOtaAutoChain,\n clearOtaAutoChainReconnectWait,\n isOtaAutoChainActive,\n otaAutoChainFingerprint,\n otaAutoChainReconnectWaitRemaining,\n stopOtaAutoChain,\n tryAdvanceOtaAutoChain,\n MAX_OTA_AUTO_CHAIN_PASSES,\n OTA_AUTO_CHAIN_RECONNECT_TIMEOUT_MS,\n} from \"./services/OtaAutoChain\"\nexport type {OtaAutoChainAdvanceResult} from \"./services/OtaAutoChain\"\nexport {\n BES_INSTALL_RESTART_MESSAGE,\n getOtaErrorMessage,\n shouldRequireGlassesRebootForBesFailure,\n shouldShowChangeWifiForOtaDownloadFailure,\n} from \"./services/OtaErrorMapping\"\n\n// Gallery read models: engine.gallery.onNotice payload types, the media\n// permission helper + display-name derivation host gallery UI uses, and the\n// glasses-camera DTO types (re-exported through the host @/types/asg shim).\nexport type {GalleryNotice, GalleryNoticeCode} from \"./services/asg/galleryNotices\"\nexport {MediaLibraryPermissions} from \"./utils/permissions/MediaLibraryPermissions\"\nexport {deriveGalleryDisplayName} from \"./utils/permissions/galleryDisplayName\"\nexport type {\n PhotoInfo,\n CaptureFile,\n CaptureGroup,\n GalleryResponse,\n ServerStatus,\n HealthResponse,\n GalleryEvent,\n} from \"./types/asg\"\n\n// Bluetooth SDK event types host UI subscribes to via engine facades (the\n// BluetoothSdk singleton passthrough itself is internal).\nexport type {PairFailureEvent, GlassesNotReadyEvent} from \"@glassly/bluetooth-sdk\"\n\n// Cloud connection status enum (read model; the connection store is internal).\nexport {WebSocketStatus} from \"./stores/connection\"\n\n// App-list hook layer + pure list helpers (the raw useAppStatusStore and\n// installAppStoreHooks wiring are internal).\nexport {\n DUMMY_APPLET,\n saveAppsOrder,\n getAppsOrder,\n sortAppsByPackageNamePriority,\n saveLastOpenTime,\n getLastOpenTime,\n sortAppsByLastOpenTime,\n useApps,\n useStart,\n useStop,\n useSetForeground,\n useClearForeground,\n useRefresh,\n useStopAll,\n useInstall,\n useUninstall,\n useActiveApps,\n useRunningAlwaysOnApps,\n useActiveBackgroundApps,\n useBackgroundApps,\n useActiveForegroundApp,\n useForegroundApp,\n useActiveBackgroundAppsCount,\n useLocalMiniApps,\n type StartOptions,\n type OrderMap,\n} from \"./stores/apps\"\n\n// Pure dev-miniapp launch-route decision (registration itself is internal).\nexport {\n decideDevLaunchRoute,\n type DecideDevLaunchOptions,\n type DevLaunchResult,\n type DevManifest,\n} from \"./utils/devMiniappLaunch\"\nexport {HardwareCompatibility, type CompatibilityResult} from \"./utils/hardware\"\nexport {BgTimer} from \"./utils/timers\"\n// Meta Neural Band: the account sign-in a claim needs (the WebView lives in the host).\nexport {\n MetaAuthError,\n authEntryUrl,\n callbackMatches,\n callbackQuery,\n decryptBlob,\n isLoginCallback,\n login,\n tokensQuery,\n type MetaSession,\n type MetaSsoTokens,\n} from \"./services/neuralBand/MetaAuth\"\nexport type {NeuralBandClaimStatus, NeuralBandHandwritingStatus} from \"./services/neuralBand/NeuralBandInput\"\n\n// Hardware types and capability profiles.\nexport {\n HardwareType,\n HardwareRequirementLevel,\n DeviceTypes,\n ControllerTypes,\n HARDWARE_CAPABILITIES,\n getModelCapabilities,\n simulatedGlasses,\n evenRealitiesG1,\n evenRealitiesG2,\n mentraLive,\n nimo,\n rayneoIO,\n vuzixZ100,\n mentraDisplay,\n} from \"./types\"\nexport type {\n HardwareRequirement,\n CameraCapabilities,\n DisplayCapabilities,\n MicrophoneCapabilities,\n SpeakerCapabilities,\n IMUCapabilities,\n ButtonCapabilities,\n LightCapabilities,\n PowerCapabilities,\n Capabilities,\n AppletType,\n AppPermissionType,\n AppletPermission,\n AppletInterface,\n ClientApp,\n} from \"./types\"\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GestureDotsService.d.ts","sourceRoot":"","sources":["../../src/services/GestureDotsService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GestureDotsService.d.ts","sourceRoot":"","sources":["../../src/services/GestureDotsService.ts"],"names":[],"mappings":"AAuDA,cAAM,kBAAkB;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,UAAU,CAAsB;IACxC,yFAAyF;IACzF,OAAO,CAAC,OAAO,CAA4D;IAC3E,kFAAkF;IAClF,OAAO,CAAC,UAAU,CAA4B;IAC9C,8EAA8E;IAC9E,OAAO,CAAC,aAAa,CAA+B;IACpD,oGAAoG;IACpG,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,MAAM,CAAwB;IAEtC,KAAK,IAAI,IAAI;IAqBb,IAAI,IAAI,IAAI;IAQZ,OAAO,CAAC,YAAY;IAOpB,uFAAuF;IACvF,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,OAAO;IAIf;;;;;OAKG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,UAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAM7E,OAAO,CAAC,YAAY;IAsDpB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;IAWlB,sFAAsF;IACtF,OAAO,CAAC,KAAK;IAgBb;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM;CAqCf;AAED,QAAA,MAAM,kBAAkB,oBAA2B,CAAA;AACnD,eAAe,kBAAkB,CAAA;AACjC,OAAO,EAAC,kBAAkB,EAAC,CAAA"}
|
|
@@ -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.
|
|
@@ -39,7 +40,15 @@ const FLASH_GLYPHS = {
|
|
|
39
40
|
swipe_right: "right",
|
|
40
41
|
};
|
|
41
42
|
/** The band's middle finger draws the filled shapes hollow. */
|
|
42
|
-
const MIDDLE_FINGER_GLYPHS = {
|
|
43
|
+
const MIDDLE_FINGER_GLYPHS = {
|
|
44
|
+
dot: "ring",
|
|
45
|
+
double: "doubleRing",
|
|
46
|
+
hold: "holdRing",
|
|
47
|
+
};
|
|
48
|
+
/** `glyph` as `finger` draws it: the middle finger's shapes are hollow. */
|
|
49
|
+
function fingerGlyph(glyph, finger) {
|
|
50
|
+
return finger === 1 ? (MIDDLE_FINGER_GLYPHS[glyph] ?? glyph) : glyph;
|
|
51
|
+
}
|
|
43
52
|
class GestureDotsService {
|
|
44
53
|
started = false;
|
|
45
54
|
flash = null;
|
|
@@ -131,12 +140,12 @@ class GestureDotsService {
|
|
|
131
140
|
if (gestureName === "touch_down")
|
|
132
141
|
press.raw = true;
|
|
133
142
|
else if (press.raw)
|
|
134
|
-
press.glyph = "hold";
|
|
143
|
+
press.glyph = fingerGlyph("hold", finger);
|
|
135
144
|
this.render();
|
|
136
145
|
return;
|
|
137
146
|
}
|
|
138
147
|
this.clearFlash();
|
|
139
|
-
this.presses.set(finger, { raw: gestureName === "touch_down", glyph:
|
|
148
|
+
this.presses.set(finger, { raw: gestureName === "touch_down", glyph: fingerGlyph("dot", finger) });
|
|
140
149
|
this.render();
|
|
141
150
|
return;
|
|
142
151
|
}
|
|
@@ -150,7 +159,7 @@ class GestureDotsService {
|
|
|
150
159
|
return;
|
|
151
160
|
}
|
|
152
161
|
const shape = FLASH_GLYPHS[gestureName];
|
|
153
|
-
const glyph = shape
|
|
162
|
+
const glyph = shape ? fingerGlyph(shape, finger) : shape;
|
|
154
163
|
// The press already showed its own tap and hold; the device's report of
|
|
155
164
|
// them follows after its double-tap window, often after release.
|
|
156
165
|
const shownByPress = gestureName === "single_tap" || gestureName === "long_press";
|
|
@@ -158,7 +167,7 @@ class GestureDotsService {
|
|
|
158
167
|
// Pinch-and-turn reports do not release a finger. A recognized hold
|
|
159
168
|
// stays visible until tap_end instead of expiring halfway through it.
|
|
160
169
|
if (gestureName === "long_press")
|
|
161
|
-
press.glyph = "hold";
|
|
170
|
+
press.glyph = fingerGlyph("hold", finger);
|
|
162
171
|
this.render();
|
|
163
172
|
return;
|
|
164
173
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GestureDotsService.js","sourceRoot":"","sources":["../../src/services/GestureDotsService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Gesture dots — a debug indicator that flashes a small glyph top-right on the\n * glasses when a touch gesture arrives, while nothing else is on the display:\n * a filled circle for a single tap, two for a double tap, an arrow for a swipe\n * (cleared after a short pulse), a bullseye for a recognized long press.\n * Controllers that report press edges (touch_down … tap_end) show the press\n * itself instead: a dot while pressed, the bullseye once held, cleared at\n * release. The Neural Band's middle finger (index 1) draws the same shapes hollow. Extracted from\n * the CFW dashboard service; it renders through\n * the ordinary scene pipeline, so it works on any positioning device (stock\n * G2 included), and is gated by the gesture_dots debug setting.\n *\n * The glyphs are pre-baked images (not text): the stock firmware's builtin\n * font has no ●/↑/↓, and a single image element with a stable id and box maps\n * to ONE re-used firmware image container — flash and idle swap its bytes\n * (data-only update, no page rebuild) instead of creating/removing containers.\n */\nimport {useDisplayStore} from \"../stores/display\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport type {SceneElementInput} from \"../utils/display/scene\"\nimport {BgTimer} from \"../utils/timers\"\nimport {GESTURE_DOT_GLYPHS, GESTURE_DOT_GLYPH_SIZE, type GestureDotGlyph} from \"./gestureDotGlyphs\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport sceneRenderer from \"./SceneRenderer\"\n\nconst DOTS_APP_ID = \"system.gesture-dots\"\n/** How long a gesture stays on the indicator. */\nconst GESTURE_FLASH_MS = 700\n/** A press-edge device's tap and hold reports trail its last edge by its double-tap window. */\nconst EDGE_REPORT_GRACE_MS = 1000\nconst MARGIN_X = 16\nconst MARGIN_TOP = 10\n/** Gestures that flash a glyph. */\nconst FLASH_GLYPHS: Record<string, GestureDotGlyph> = {\n single_tap: \"dot\",\n double_tap: \"double\",\n long_press: \"hold\",\n swipe_up: \"up\",\n swipe_down: \"down\",\n swipe_left: \"left\",\n swipe_right: \"right\",\n}\n/** The band's middle finger draws the filled shapes hollow. */\nconst MIDDLE_FINGER_GLYPHS: Partial<Record<GestureDotGlyph, GestureDotGlyph>> = {dot: \"ring\", double: \"doubleRing\"}\n\nclass GestureDotsService {\n private started = false\n private flash: GestureDotGlyph | null = null\n private flashTimer: number | null = null\n /** Raw controller holds survive hold recognition/dial events until their own release. */\n private presses = new Map<number, {raw: boolean; glyph: GestureDotGlyph}>()\n /** When each finger last sent a press edge (touch_down, or tap_end after one). */\n private lastEdgeAt = new Map<number, number>()\n /** Avoid sending identical images for successive phases of the same press. */\n private renderedGlyph: GestureDotGlyph | null = null\n /** Whether the indicator scene currently has anything on it (needs a clear when the flash ends). */\n private visible = false\n private unsubs: Array<() => void> = []\n\n start(): void {\n if (this.started) return\n this.started = true\n this.unsubs.push(\n // The indicator owns the screen only while it is empty: drop our\n // retained state when something else takes over, and clear any\n // leftover flash when the display empties again.\n localDisplayManager.onActiveDisplayChange((active) => {\n if (active) this.relinquish()\n else this.render()\n }),\n // Overlays do not change the retained main display's occupancy.\n useDisplayStore.subscribe(\n (state) => state.overlayOwner,\n (owner) => {\n if (owner !== null) this.relinquish()\n },\n ),\n )\n }\n\n stop(): void {\n for (const unsub of this.unsubs) unsub()\n this.unsubs = []\n this.relinquish()\n this.lastEdgeAt.clear()\n this.started = false\n }\n\n private resetGesture(): void {\n if (this.flashTimer !== null) BgTimer.clearTimeout(this.flashTimer)\n this.flashTimer = null\n this.flash = null\n this.presses.clear()\n }\n\n /** Another surface owns the display; forget the indicator without painting over it. */\n private relinquish(): void {\n this.resetGesture()\n this.visible = false\n this.renderedGlyph = null\n sceneRenderer.clearApp(DOTS_APP_ID)\n this.trace(\"relinquish\")\n }\n\n private enabled(): boolean {\n return useSettingsStore.getState().getSetting(SETTINGS.gesture_dots.key) === true\n }\n\n /**\n * Flash a gesture on the indicator. Other gesture names are ignored.\n * Claimed gestures cancel any earlier press/flash without starting a new\n * one: the claimant may also consume the release edge. `fingerIndex` is the\n * Neural Band's finger on its pinches and press edges (1 = middle).\n */\n noteGesture(gestureName: string, claimed = false, fingerIndex?: number): void {\n if (!this.started || !this.enabled()) return\n this.applyGesture(gestureName, claimed, fingerIndex)\n this.trace(\"input\", {gestureName, claimed})\n }\n\n private applyGesture(gestureName: string, claimed: boolean, fingerIndex?: number): void {\n if (localDisplayManager.hasActiveDisplay() || useDisplayStore.getState().overlayOwner !== null) {\n this.relinquish()\n return\n }\n if (claimed) {\n this.resetGesture()\n this.render()\n return\n }\n const finger = fingerIndex ?? 0\n const press = this.presses.get(finger)\n if (gestureName === \"touch_down\" || gestureName === \"tap_start\") {\n if (gestureName === \"touch_down\") this.lastEdgeAt.set(finger, Date.now())\n if (press) {\n // Both reports describe one press: after touch_down, tap_start means it is held.\n if (gestureName === \"touch_down\") press.raw = true\n else if (press.raw) press.glyph = \"hold\"\n this.render()\n return\n }\n this.clearFlash()\n this.presses.set(finger, {raw: gestureName === \"touch_down\", glyph: finger === 1 ? \"ring\" : \"dot\"})\n this.render()\n return\n }\n if (gestureName === \"tap_end\") {\n if (!press) return\n this.presses.delete(finger)\n if (press.raw) this.lastEdgeAt.set(finger, Date.now())\n this.render()\n return\n }\n const shape = FLASH_GLYPHS[gestureName]\n const glyph = shape && finger === 1 ? MIDDLE_FINGER_GLYPHS[shape] ?? shape : shape\n // The press already showed its own tap and hold; the device's report of\n // them follows after its double-tap window, often after release.\n const shownByPress = gestureName === \"single_tap\" || gestureName === \"long_press\"\n if (press?.raw && (!glyph || shownByPress)) {\n // Pinch-and-turn reports do not release a finger. A recognized hold\n // stays visible until tap_end instead of expiring halfway through it.\n if (gestureName === \"long_press\") press.glyph = \"hold\"\n this.render()\n return\n }\n const lastEdgeAt = this.lastEdgeAt.get(finger)\n if (!press && shownByPress && lastEdgeAt !== undefined && Date.now() - lastEdgeAt < EDGE_REPORT_GRACE_MS) return\n // Completed taps/swipes become one continuous pulse, even if the device\n // omits tap_end. Older tap_start-only devices retain the same fallback.\n this.presses.delete(finger)\n if (glyph) this.startFlash(glyph)\n this.render()\n }\n\n private clearFlash(): void {\n if (this.flashTimer !== null) BgTimer.clearTimeout(this.flashTimer)\n this.flashTimer = null\n this.flash = null\n }\n\n private startFlash(glyph: GestureDotGlyph): void {\n this.clearFlash()\n this.flash = glyph\n this.flashTimer = BgTimer.setTimeout(() => {\n this.flashTimer = null\n this.flash = null\n this.render()\n this.trace(\"flash-ended\")\n }, GESTURE_FLASH_MS)\n }\n\n /** Debug setting only; no payloads or retained history. Correlate seq with G2PERF. */\n private trace(reason: string, details: Record<string, unknown> = {}): void {\n if (!this.enabled()) return\n console.log(\n \"GESTUREDOTS \" +\n JSON.stringify({\n t: Date.now(),\n reason,\n held: this.presses.size > 0,\n flash: this.flash,\n overlay: useDisplayStore.getState().overlayOwner,\n active: localDisplayManager.hasActiveDisplay(),\n ...details,\n }),\n )\n }\n\n /**\n * Paint or clear the indicator. Nothing is drawn while anything else is on\n * the glasses (miniapp frame or system screen) or when no gesture was just\n * received. The top-right anchor resolves against the device's real canvas,\n * so no size math here.\n *\n * Between flashes the element STAYS in the scene with the blank glyph:\n * removing it would tear down the firmware image container and rebuild the\n * page on every flash (a rebuild storm on stock firmware). Only disabling\n * the setting removes the element outright.\n */\n private render(): void {\n if (!this.started) return\n if (localDisplayManager.hasActiveDisplay() || useDisplayStore.getState().overlayOwner !== null) return\n const shown = Array.from(this.presses.values()).at(-1)?.glyph ?? this.flash\n if (!this.enabled()) {\n if (this.visible) {\n this.visible = false\n this.renderedGlyph = null\n sceneRenderer.emitScene(DOTS_APP_ID, \"main\", [])\n }\n return\n }\n if (!shown && !this.visible) return\n const glyph = shown ?? \"blank\"\n if (glyph === this.renderedGlyph) return\n const elements: SceneElementInput[] = [\n {\n type: \"image\",\n id: \"gesture-dot\",\n box: {\n x: MARGIN_X,\n y: MARGIN_TOP,\n w: GESTURE_DOT_GLYPH_SIZE,\n h: GESTURE_DOT_GLYPH_SIZE,\n anchor: \"top-right\",\n },\n data: GESTURE_DOT_GLYPHS[glyph],\n },\n ]\n this.visible = true\n this.renderedGlyph = glyph\n const result = sceneRenderer.emitScene(DOTS_APP_ID, \"main\", elements)\n this.trace(\"render\", {\n glyph,\n ...(result?.kind === \"scene\" ? {seq: result.seq, sent: result.sent} : {}),\n })\n }\n}\n\nconst gestureDotsService = new GestureDotsService()\nexport default gestureDotsService\nexport {GestureDotsService}\n"]}
|
|
1
|
+
{"version":3,"file":"GestureDotsService.js","sourceRoot":"","sources":["../../src/services/GestureDotsService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Gesture dots — a debug indicator that flashes a small glyph top-right on the\n * glasses when a touch gesture arrives, while nothing else is on the display:\n * a filled circle for a single tap, two for a double tap, an arrow for a swipe\n * (cleared after a short pulse), a bullseye for a recognized long press.\n * Controllers that report press edges (touch_down … tap_end) show the press\n * itself instead: a dot while pressed, the bullseye once held, cleared at\n * release. The Neural Band's middle finger (index 1) draws the same shapes\n * hollow: a ring for its tap, the bullseye without its center for its hold. Extracted from\n * the CFW dashboard service; it renders through\n * the ordinary scene pipeline, so it works on any positioning device (stock\n * G2 included), and is gated by the gesture_dots debug setting.\n *\n * The glyphs are pre-baked images (not text): the stock firmware's builtin\n * font has no ●/↑/↓, and a single image element with a stable id and box maps\n * to ONE re-used firmware image container — flash and idle swap its bytes\n * (data-only update, no page rebuild) instead of creating/removing containers.\n */\nimport {useDisplayStore} from \"../stores/display\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport type {SceneElementInput} from \"../utils/display/scene\"\nimport {BgTimer} from \"../utils/timers\"\nimport {GESTURE_DOT_GLYPHS, GESTURE_DOT_GLYPH_SIZE, type GestureDotGlyph} from \"./gestureDotGlyphs\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport sceneRenderer from \"./SceneRenderer\"\n\nconst DOTS_APP_ID = \"system.gesture-dots\"\n/** How long a gesture stays on the indicator. */\nconst GESTURE_FLASH_MS = 700\n/** A press-edge device's tap and hold reports trail its last edge by its double-tap window. */\nconst EDGE_REPORT_GRACE_MS = 1000\nconst MARGIN_X = 16\nconst MARGIN_TOP = 10\n/** Gestures that flash a glyph. */\nconst FLASH_GLYPHS: Record<string, GestureDotGlyph> = {\n single_tap: \"dot\",\n double_tap: \"double\",\n long_press: \"hold\",\n swipe_up: \"up\",\n swipe_down: \"down\",\n swipe_left: \"left\",\n swipe_right: \"right\",\n}\n/** The band's middle finger draws the filled shapes hollow. */\nconst MIDDLE_FINGER_GLYPHS: Partial<Record<GestureDotGlyph, GestureDotGlyph>> = {\n dot: \"ring\",\n double: \"doubleRing\",\n hold: \"holdRing\",\n}\n\n/** `glyph` as `finger` draws it: the middle finger's shapes are hollow. */\nfunction fingerGlyph(glyph: GestureDotGlyph, finger: number): GestureDotGlyph {\n return finger === 1 ? (MIDDLE_FINGER_GLYPHS[glyph] ?? glyph) : glyph\n}\n\nclass GestureDotsService {\n private started = false\n private flash: GestureDotGlyph | null = null\n private flashTimer: number | null = null\n /** Raw controller holds survive hold recognition/dial events until their own release. */\n private presses = new Map<number, {raw: boolean; glyph: GestureDotGlyph}>()\n /** When each finger last sent a press edge (touch_down, or tap_end after one). */\n private lastEdgeAt = new Map<number, number>()\n /** Avoid sending identical images for successive phases of the same press. */\n private renderedGlyph: GestureDotGlyph | null = null\n /** Whether the indicator scene currently has anything on it (needs a clear when the flash ends). */\n private visible = false\n private unsubs: Array<() => void> = []\n\n start(): void {\n if (this.started) return\n this.started = true\n this.unsubs.push(\n // The indicator owns the screen only while it is empty: drop our\n // retained state when something else takes over, and clear any\n // leftover flash when the display empties again.\n localDisplayManager.onActiveDisplayChange((active) => {\n if (active) this.relinquish()\n else this.render()\n }),\n // Overlays do not change the retained main display's occupancy.\n useDisplayStore.subscribe(\n (state) => state.overlayOwner,\n (owner) => {\n if (owner !== null) this.relinquish()\n },\n ),\n )\n }\n\n stop(): void {\n for (const unsub of this.unsubs) unsub()\n this.unsubs = []\n this.relinquish()\n this.lastEdgeAt.clear()\n this.started = false\n }\n\n private resetGesture(): void {\n if (this.flashTimer !== null) BgTimer.clearTimeout(this.flashTimer)\n this.flashTimer = null\n this.flash = null\n this.presses.clear()\n }\n\n /** Another surface owns the display; forget the indicator without painting over it. */\n private relinquish(): void {\n this.resetGesture()\n this.visible = false\n this.renderedGlyph = null\n sceneRenderer.clearApp(DOTS_APP_ID)\n this.trace(\"relinquish\")\n }\n\n private enabled(): boolean {\n return useSettingsStore.getState().getSetting(SETTINGS.gesture_dots.key) === true\n }\n\n /**\n * Flash a gesture on the indicator. Other gesture names are ignored.\n * Claimed gestures cancel any earlier press/flash without starting a new\n * one: the claimant may also consume the release edge. `fingerIndex` is the\n * Neural Band's finger on its pinches and press edges (1 = middle).\n */\n noteGesture(gestureName: string, claimed = false, fingerIndex?: number): void {\n if (!this.started || !this.enabled()) return\n this.applyGesture(gestureName, claimed, fingerIndex)\n this.trace(\"input\", {gestureName, claimed})\n }\n\n private applyGesture(gestureName: string, claimed: boolean, fingerIndex?: number): void {\n if (localDisplayManager.hasActiveDisplay() || useDisplayStore.getState().overlayOwner !== null) {\n this.relinquish()\n return\n }\n if (claimed) {\n this.resetGesture()\n this.render()\n return\n }\n const finger = fingerIndex ?? 0\n const press = this.presses.get(finger)\n if (gestureName === \"touch_down\" || gestureName === \"tap_start\") {\n if (gestureName === \"touch_down\") this.lastEdgeAt.set(finger, Date.now())\n if (press) {\n // Both reports describe one press: after touch_down, tap_start means it is held.\n if (gestureName === \"touch_down\") press.raw = true\n else if (press.raw) press.glyph = fingerGlyph(\"hold\", finger)\n this.render()\n return\n }\n this.clearFlash()\n this.presses.set(finger, {raw: gestureName === \"touch_down\", glyph: fingerGlyph(\"dot\", finger)})\n this.render()\n return\n }\n if (gestureName === \"tap_end\") {\n if (!press) return\n this.presses.delete(finger)\n if (press.raw) this.lastEdgeAt.set(finger, Date.now())\n this.render()\n return\n }\n const shape = FLASH_GLYPHS[gestureName]\n const glyph = shape ? fingerGlyph(shape, finger) : shape\n // The press already showed its own tap and hold; the device's report of\n // them follows after its double-tap window, often after release.\n const shownByPress = gestureName === \"single_tap\" || gestureName === \"long_press\"\n if (press?.raw && (!glyph || shownByPress)) {\n // Pinch-and-turn reports do not release a finger. A recognized hold\n // stays visible until tap_end instead of expiring halfway through it.\n if (gestureName === \"long_press\") press.glyph = fingerGlyph(\"hold\", finger)\n this.render()\n return\n }\n const lastEdgeAt = this.lastEdgeAt.get(finger)\n if (!press && shownByPress && lastEdgeAt !== undefined && Date.now() - lastEdgeAt < EDGE_REPORT_GRACE_MS) return\n // Completed taps/swipes become one continuous pulse, even if the device\n // omits tap_end. Older tap_start-only devices retain the same fallback.\n this.presses.delete(finger)\n if (glyph) this.startFlash(glyph)\n this.render()\n }\n\n private clearFlash(): void {\n if (this.flashTimer !== null) BgTimer.clearTimeout(this.flashTimer)\n this.flashTimer = null\n this.flash = null\n }\n\n private startFlash(glyph: GestureDotGlyph): void {\n this.clearFlash()\n this.flash = glyph\n this.flashTimer = BgTimer.setTimeout(() => {\n this.flashTimer = null\n this.flash = null\n this.render()\n this.trace(\"flash-ended\")\n }, GESTURE_FLASH_MS)\n }\n\n /** Debug setting only; no payloads or retained history. Correlate seq with G2PERF. */\n private trace(reason: string, details: Record<string, unknown> = {}): void {\n if (!this.enabled()) return\n console.log(\n \"GESTUREDOTS \" +\n JSON.stringify({\n t: Date.now(),\n reason,\n held: this.presses.size > 0,\n flash: this.flash,\n overlay: useDisplayStore.getState().overlayOwner,\n active: localDisplayManager.hasActiveDisplay(),\n ...details,\n }),\n )\n }\n\n /**\n * Paint or clear the indicator. Nothing is drawn while anything else is on\n * the glasses (miniapp frame or system screen) or when no gesture was just\n * received. The top-right anchor resolves against the device's real canvas,\n * so no size math here.\n *\n * Between flashes the element STAYS in the scene with the blank glyph:\n * removing it would tear down the firmware image container and rebuild the\n * page on every flash (a rebuild storm on stock firmware). Only disabling\n * the setting removes the element outright.\n */\n private render(): void {\n if (!this.started) return\n if (localDisplayManager.hasActiveDisplay() || useDisplayStore.getState().overlayOwner !== null) return\n const shown = Array.from(this.presses.values()).at(-1)?.glyph ?? this.flash\n if (!this.enabled()) {\n if (this.visible) {\n this.visible = false\n this.renderedGlyph = null\n sceneRenderer.emitScene(DOTS_APP_ID, \"main\", [])\n }\n return\n }\n if (!shown && !this.visible) return\n const glyph = shown ?? \"blank\"\n if (glyph === this.renderedGlyph) return\n const elements: SceneElementInput[] = [\n {\n type: \"image\",\n id: \"gesture-dot\",\n box: {\n x: MARGIN_X,\n y: MARGIN_TOP,\n w: GESTURE_DOT_GLYPH_SIZE,\n h: GESTURE_DOT_GLYPH_SIZE,\n anchor: \"top-right\",\n },\n data: GESTURE_DOT_GLYPHS[glyph],\n },\n ]\n this.visible = true\n this.renderedGlyph = glyph\n const result = sceneRenderer.emitScene(DOTS_APP_ID, \"main\", elements)\n this.trace(\"render\", {\n glyph,\n ...(result?.kind === \"scene\" ? {seq: result.seq, sent: result.sent} : {}),\n })\n }\n}\n\nconst gestureDotsService = new GestureDotsService()\nexport default gestureDotsService\nexport {GestureDotsService}\n"]}
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* 24×24 8-bit grayscale PNGs (white on black) for the gesture-dots indicator.
|
|
4
4
|
*/
|
|
5
5
|
export declare const GESTURE_DOT_GLYPH_SIZE = 24;
|
|
6
|
-
export type GestureDotGlyph = "dot" | "double" | "ring" | "doubleRing" | "up" | "down" | "left" | "right" | "hold" | "blank";
|
|
6
|
+
export type GestureDotGlyph = "dot" | "double" | "ring" | "doubleRing" | "up" | "down" | "left" | "right" | "hold" | "holdRing" | "blank";
|
|
7
7
|
export declare const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string>;
|
|
8
8
|
//# sourceMappingURL=gestureDotGlyphs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gestureDotGlyphs.d.ts","sourceRoot":"","sources":["../../src/services/gestureDotGlyphs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAA;AAExC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"gestureDotGlyphs.d.ts","sourceRoot":"","sources":["../../src/services/gestureDotGlyphs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAA;AAExC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAA;AAEzI,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAY9D,CAAA"}
|
|
@@ -13,6 +13,7 @@ export const GESTURE_DOT_GLYPHS = {
|
|
|
13
13
|
left: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAI0lEQVR4nGNgoCv4j0sch8RAiTP8RwPESOAwajDI4JKgGQAAKO05x7DqJxIAAAAASUVORK5CYII=",
|
|
14
14
|
right: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIElEQVR4nGNgoDf4j1NiMMn8RwOEJYizZKDEcQc7bQAAS7w5x+ro2lsAAAAASUVORK5CYII=",
|
|
15
15
|
hold: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAR0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKl0Z0Lof7DKbgMhBpQCZzOxedBHEGCMxAJBTXhKGRAA9hFMQEANr7jHQU9fO0AAAAASUVORK5CYII=",
|
|
16
|
+
holdRing: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAQ0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKlMd2IVQNMaEAlcDoXnwdxBAnOQCQU1ISjEIvjsYhiAgAo9KdZzePY3AAAAABJRU5ErkJggg==",
|
|
16
17
|
blank: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC",
|
|
17
18
|
};
|
|
18
19
|
//# sourceMappingURL=gestureDotGlyphs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gestureDotGlyphs.js","sourceRoot":"","sources":["../../src/services/gestureDotGlyphs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAA;AAIxC,MAAM,CAAC,MAAM,kBAAkB,GAAoC;IACjE,GAAG,EAAE,8IAA8I;IACnJ,MAAM,EAAE,kHAAkH;IAC1H,IAAI,EAAE,sJAAsJ;IAC5J,UAAU,EAAE,8HAA8H;IAC1I,EAAE,EAAE,8IAA8I;IAClJ,IAAI,EAAE,0IAA0I;IAChJ,IAAI,EAAE,8HAA8H;IACpI,KAAK,EAAE,0HAA0H;IACjI,IAAI,EAAE,8KAA8K;IACpL,KAAK,EAAE,kGAAkG;CAC1G,CAAA","sourcesContent":["/**\n * GENERATED by scripts/gen-gesture-dot-glyphs.mjs — do not edit by hand.\n * 24×24 8-bit grayscale PNGs (white on black) for the gesture-dots indicator.\n */\nexport const GESTURE_DOT_GLYPH_SIZE = 24\n\nexport type GestureDotGlyph = \"dot\" | \"double\" | \"ring\" | \"doubleRing\" | \"up\" | \"down\" | \"left\" | \"right\" | \"hold\" | \"blank\"\n\nexport const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string> = {\n dot: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALklEQVR4nM2QsQ0AAAjC/P/pmrhqZ+xIF6DqBQyWbwO3gduAmKjQuj7QL/ETEzQmMptl7Q9NBAAAAABJRU5ErkJggg==\",\n double: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAG0lEQVR4nGNgGD7gPxjgYkN4yOyBlcDp3GEBAB3sd4lPaQxDAAAAAElFTkSuQmCC\",\n ring: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAANElEQVR4nGNgGBTgPxjgEseUgQphyCD4qDL/kSX+Y9WApoWqEjgsx+lc3B7EHSS4A3EgAAC+cEu1JTNREQAAAABJRU5ErkJggg==\",\n doubleRing: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIklEQVR4nGNgGD7gPxjgYkN4yGwGmBA6SV0JHJbjdO6wAADBMlep8zl7TAAAAABJRU5ErkJggg==\",\n up: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAMElEQVR4nGNgoCv4////f1zi2GT+/4ciTHE4RhdHIlDFUUhkcTQKQx9WBw8PCVoBAIcbOcf3xeeBAAAAAElFTkSuQmCC\",\n down: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALUlEQVR4nGNgoC/4/3+4SkBFUCkkNjKJIoMg0GRgGEMGgrC4CQSwuxanR2gEAO1/Ocfgp8uvAAAAAElFTkSuQmCC\",\n left: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAI0lEQVR4nGNgoCv4j0sch8RAiTP8RwPESOAwajDI4JKgGQAAKO05x7DqJxIAAAAASUVORK5CYII=\",\n right: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIElEQVR4nGNgoDf4j1NiMMn8RwOEJYizZKDEcQc7bQAAS7w5x+ro2lsAAAAASUVORK5CYII=\",\n hold: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAR0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKl0Z0Lof7DKbgMhBpQCZzOxedBHEGCMxAJBTXhKGRAA9hFMQEANr7jHQU9fO0AAAAASUVORK5CYII=\",\n blank: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC\",\n}\n"]}
|
|
1
|
+
{"version":3,"file":"gestureDotGlyphs.js","sourceRoot":"","sources":["../../src/services/gestureDotGlyphs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAA;AAIxC,MAAM,CAAC,MAAM,kBAAkB,GAAoC;IACjE,GAAG,EAAE,8IAA8I;IACnJ,MAAM,EAAE,kHAAkH;IAC1H,IAAI,EAAE,sJAAsJ;IAC5J,UAAU,EAAE,8HAA8H;IAC1I,EAAE,EAAE,8IAA8I;IAClJ,IAAI,EAAE,0IAA0I;IAChJ,IAAI,EAAE,8HAA8H;IACpI,KAAK,EAAE,0HAA0H;IACjI,IAAI,EAAE,8KAA8K;IACpL,QAAQ,EAAE,0KAA0K;IACpL,KAAK,EAAE,kGAAkG;CAC1G,CAAA","sourcesContent":["/**\n * GENERATED by scripts/gen-gesture-dot-glyphs.mjs — do not edit by hand.\n * 24×24 8-bit grayscale PNGs (white on black) for the gesture-dots indicator.\n */\nexport const GESTURE_DOT_GLYPH_SIZE = 24\n\nexport type GestureDotGlyph = \"dot\" | \"double\" | \"ring\" | \"doubleRing\" | \"up\" | \"down\" | \"left\" | \"right\" | \"hold\" | \"holdRing\" | \"blank\"\n\nexport const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string> = {\n dot: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALklEQVR4nM2QsQ0AAAjC/P/pmrhqZ+xIF6DqBQyWbwO3gduAmKjQuj7QL/ETEzQmMptl7Q9NBAAAAABJRU5ErkJggg==\",\n double: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAG0lEQVR4nGNgGD7gPxjgYkN4yOyBlcDp3GEBAB3sd4lPaQxDAAAAAElFTkSuQmCC\",\n ring: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAANElEQVR4nGNgGBTgPxjgEseUgQphyCD4qDL/kSX+Y9WApoWqEjgsx+lc3B7EHSS4A3EgAAC+cEu1JTNREQAAAABJRU5ErkJggg==\",\n doubleRing: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIklEQVR4nGNgGD7gPxjgYkN4yGwGmBA6SV0JHJbjdO6wAADBMlep8zl7TAAAAABJRU5ErkJggg==\",\n up: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAMElEQVR4nGNgoCv4////f1zi2GT+/4ciTHE4RhdHIlDFUUhkcTQKQx9WBw8PCVoBAIcbOcf3xeeBAAAAAElFTkSuQmCC\",\n down: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALUlEQVR4nGNgoC/4/3+4SkBFUCkkNjKJIoMg0GRgGEMGgrC4CQSwuxanR2gEAO1/Ocfgp8uvAAAAAElFTkSuQmCC\",\n left: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAI0lEQVR4nGNgoCv4j0sch8RAiTP8RwPESOAwajDI4JKgGQAAKO05x7DqJxIAAAAASUVORK5CYII=\",\n right: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAIElEQVR4nGNgoDf4j1NiMMn8RwOEJYizZKDEcQc7bQAAS7w5x+ro2lsAAAAASUVORK5CYII=\",\n hold: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAR0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKl0Z0Lof7DKbgMhBpQCZzOxedBHEGCMxAJBTXhKGRAA9hFMQEANr7jHQU9fO0AAAAASUVORK5CYII=\",\n holdRing: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAQ0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKlMd2IVQNMaEAlcDoXnwdxBAnOQCQU1ISjEIvjsYhiAgAo9KdZzePY3AAAAABJRU5ErkJggg==\",\n blank: \"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC\",\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/timers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/timers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,UAAU,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/timers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/timers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,UAAU,CAAA","sourcesContent":["export {BgTimer} from \"./timers\"\n"]}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export declare class BgTimer {
|
|
2
|
-
static setInterval(callback: () => void, delay: number): number;
|
|
3
|
-
static clearInterval(intervalId: number): void;
|
|
4
2
|
static setTimeout(callback: () => void, delay: number): number;
|
|
5
|
-
static clearTimeout(
|
|
3
|
+
static clearTimeout(id: number): void;
|
|
4
|
+
static setInterval(callback: () => void, delay: number): number;
|
|
5
|
+
static clearInterval(id: number): void;
|
|
6
6
|
}
|
|
7
|
-
export declare function throttle<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void;
|
|
8
|
-
export declare function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void;
|
|
9
7
|
//# sourceMappingURL=timers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"AA+GA,qBAAa,OAAO;IAClB,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAI9D,MAAM,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIrC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAI/D,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAGvC"}
|
|
@@ -1,164 +1,114 @@
|
|
|
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
|
+
const TIMER_METHODS = ["setTimeout", "clearTimeout", "setInterval", "clearInterval"];
|
|
17
|
+
const jsTimers = {
|
|
18
|
+
setTimeout: (callback, delay) => setTimeout(callback, delay),
|
|
19
|
+
clearTimeout: (id) => clearTimeout(id),
|
|
20
|
+
setInterval: (callback, delay) => setInterval(callback, delay),
|
|
21
|
+
clearInterval: (id) => clearInterval(id),
|
|
22
|
+
};
|
|
31
23
|
let reactNative;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
// undefined = not looked up yet, null = unavailable (JS timers from here on).
|
|
25
|
+
let nativeTimers;
|
|
26
|
+
let reported = false;
|
|
27
|
+
function loadReactNative() {
|
|
28
|
+
if (reactNative === undefined) {
|
|
29
|
+
try {
|
|
30
|
+
reactNative = require("react-native");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
reactNative = null;
|
|
34
|
+
}
|
|
41
35
|
}
|
|
42
36
|
return reactNative;
|
|
43
37
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
let nitroTimer;
|
|
48
|
-
let nitroDisabled = false;
|
|
49
|
-
let failedLoud = false;
|
|
50
|
-
/**
|
|
51
|
-
* The native background timer is unavailable — say so ONCE, loudly, with the
|
|
52
|
-
* remediation. The JS-timer fallback keeps foreground behavior working, but
|
|
53
|
-
* everything timing-driven freezes while the app is backgrounded, which
|
|
54
|
-
* presents as phantom miniapp bugs (frozen captions, missed wake words,
|
|
55
|
-
* watchdog kills on resume). A quiet warning here has already cost a full
|
|
56
|
-
* debugging day; never downgrade this to console.warn.
|
|
57
|
-
*/
|
|
58
|
-
function failUnavailable(reason) {
|
|
59
|
-
if (failedLoud) {
|
|
38
|
+
function reportUnavailable(reason) {
|
|
39
|
+
if (reported)
|
|
60
40
|
return;
|
|
61
|
-
|
|
62
|
-
|
|
41
|
+
reported = true;
|
|
42
|
+
const rn = loadReactNative();
|
|
43
|
+
const platform = rn?.Platform.OS === "ios" ? "ios" : "android";
|
|
63
44
|
const message = `BgTimer: native background timer unavailable (${reason}). ` +
|
|
64
|
-
|
|
45
|
+
`Backgrounded behavior IS BROKEN until you rebuild the app: run \`bun ${platform}\`. ` +
|
|
65
46
|
"Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded.";
|
|
66
47
|
console.error(message);
|
|
67
|
-
if (
|
|
68
|
-
// A stale dev client may
|
|
69
|
-
//
|
|
70
|
-
// is the actionable one: it names the fix.
|
|
48
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
49
|
+
// A stale dev client may also red-box inside the library itself; this
|
|
50
|
+
// alert is the one that names the fix.
|
|
71
51
|
try {
|
|
72
|
-
|
|
52
|
+
rn?.Alert?.alert("Background timers unavailable", message);
|
|
73
53
|
}
|
|
74
54
|
catch {
|
|
75
|
-
|
|
55
|
+
// Headless runtime: the console.error stands.
|
|
76
56
|
}
|
|
77
57
|
}
|
|
78
58
|
}
|
|
79
|
-
function
|
|
80
|
-
if (
|
|
59
|
+
function loadNativeTimers() {
|
|
60
|
+
if (nativeTimers !== undefined)
|
|
61
|
+
return nativeTimers;
|
|
62
|
+
const platform = loadReactNative()?.Platform.OS;
|
|
63
|
+
if (platform !== "android" && platform !== "ios") {
|
|
64
|
+
nativeTimers = null;
|
|
81
65
|
return null;
|
|
82
66
|
}
|
|
83
|
-
if (nitroTimer !== undefined) {
|
|
84
|
-
return nitroTimer;
|
|
85
|
-
}
|
|
86
67
|
try {
|
|
87
68
|
const { isRuntimeAlive } = require("react-native-nitro-modules");
|
|
88
|
-
if (typeof isRuntimeAlive === "function" && !isRuntimeAlive())
|
|
89
|
-
|
|
90
|
-
failUnavailable("nitro runtime is not alive");
|
|
91
|
-
return nitroTimer;
|
|
92
|
-
}
|
|
69
|
+
if (typeof isRuntimeAlive === "function" && !isRuntimeAlive())
|
|
70
|
+
throw new Error("nitro runtime is not alive");
|
|
93
71
|
const { BackgroundTimer } = require("react-native-nitro-bg-timer");
|
|
94
|
-
|
|
95
|
-
BackgroundTimer
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
typeof BackgroundTimer.clearInterval === "function"
|
|
100
|
-
? BackgroundTimer
|
|
101
|
-
: null;
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
nitroTimer = null;
|
|
105
|
-
nitroDisabled = true;
|
|
72
|
+
for (const method of TIMER_METHODS) {
|
|
73
|
+
if (typeof BackgroundTimer?.[method] !== "function")
|
|
74
|
+
throw new Error(`BackgroundTimer.${method} missing`);
|
|
75
|
+
}
|
|
76
|
+
nativeTimers = BackgroundTimer;
|
|
106
77
|
}
|
|
107
|
-
|
|
108
|
-
|
|
78
|
+
catch (error) {
|
|
79
|
+
nativeTimers = null;
|
|
80
|
+
reportUnavailable(error instanceof Error ? error.message : String(error));
|
|
109
81
|
}
|
|
110
|
-
return
|
|
82
|
+
return nativeTimers;
|
|
111
83
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
84
|
+
// A native call that throws mid-session is new information: drop to JS timers
|
|
85
|
+
// and announce again.
|
|
86
|
+
function call(run) {
|
|
87
|
+
const native = loadNativeTimers();
|
|
88
|
+
if (!native)
|
|
89
|
+
return run(jsTimers);
|
|
117
90
|
try {
|
|
118
|
-
return run(
|
|
91
|
+
return run(native);
|
|
119
92
|
}
|
|
120
93
|
catch (error) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return fallback();
|
|
94
|
+
nativeTimers = null;
|
|
95
|
+
reported = false;
|
|
96
|
+
reportUnavailable(`native timer call threw: ${String(error)}`);
|
|
97
|
+
return run(jsTimers);
|
|
126
98
|
}
|
|
127
99
|
}
|
|
128
100
|
export class BgTimer {
|
|
129
|
-
static
|
|
130
|
-
return
|
|
101
|
+
static setTimeout(callback, delay) {
|
|
102
|
+
return call((timers) => timers.setTimeout(callback, delay));
|
|
131
103
|
}
|
|
132
|
-
static
|
|
133
|
-
|
|
104
|
+
static clearTimeout(id) {
|
|
105
|
+
call((timers) => timers.clearTimeout(id));
|
|
134
106
|
}
|
|
135
|
-
static
|
|
136
|
-
return
|
|
107
|
+
static setInterval(callback, delay) {
|
|
108
|
+
return call((timers) => timers.setInterval(callback, delay));
|
|
137
109
|
}
|
|
138
|
-
static
|
|
139
|
-
|
|
110
|
+
static clearInterval(id) {
|
|
111
|
+
call((timers) => timers.clearInterval(id));
|
|
140
112
|
}
|
|
141
113
|
}
|
|
142
|
-
export function throttle(fn, ms) {
|
|
143
|
-
let lastCalled = 0;
|
|
144
|
-
return (...args) => {
|
|
145
|
-
const now = Date.now();
|
|
146
|
-
if (now - lastCalled >= ms) {
|
|
147
|
-
lastCalled = now;
|
|
148
|
-
fn(...args);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
export function debounce(fn, ms) {
|
|
153
|
-
let timeoutId = null;
|
|
154
|
-
return (...args) => {
|
|
155
|
-
if (timeoutId) {
|
|
156
|
-
BgTimer.clearTimeout(timeoutId);
|
|
157
|
-
}
|
|
158
|
-
timeoutId = BgTimer.setTimeout(() => {
|
|
159
|
-
fn(...args);
|
|
160
|
-
timeoutId = null;
|
|
161
|
-
}, ms);
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
114
|
//# sourceMappingURL=timers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timers.js","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"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","sourcesContent":["// BgTimer — background-safe timers for the engine.\n//\n// Everything timing-critical in the engine runs through this class: the\n// miniapp liveness watchdog, display durationMs expiries, boot windows,\n// auth-token refresh. On Android, React Native PAUSES plain JS timers while\n// the app is backgrounded, so those features only keep working in the\n// background when the native implementation (react-native-nitro-bg-timer)\n// is active.\n//\n// Who actually gets native timers:\n// - Android, dev AND release: always attempted — dev must match production\n// background behavior. There is no opt-in/opt-out env var. If the native\n// module is unavailable (a dev client whose binary predates it, or a\n// broken release binary), the failure is LOUD: a console.error with the\n// remediation, plus a blocking dev alert. The JS-timer fallback still\n// engages so foreground behavior keeps working, but backgrounded\n// behavior is broken until the native rebuild — the error says exactly\n// that. (A silent dev fallback previously cost a full debugging day of\n// phantom \"zombie miniapp\" bugs; see OS-1790.)\n// - iOS: never, dev or prod — the package is disabled pending\n// https://github.com/tconns/react-native-nitro-bg-timer/issues/2. iOS\n// suspends the whole process in background anyway, so background timing\n// there is handled by native per-device queues, not JS timers.\n//\n// react-native is loaded lazily, not imported. Every engine service runs its\n// timers through this module, and the engine's bun test suites load those\n// services in a plain JS runtime that cannot parse react-native's Flow\n// source. A static import would force every such suite to mock this module;\n// with the lazy load, a runtime without react-native simply gets the JS\n// timers, which is the correct answer there anyway.\n\ntype ReactNativeSubset = {\n Platform: {OS: string}\n Alert?: {alert: (title: string, message?: string) => void}\n}\n\nlet reactNative: ReactNativeSubset | null | undefined\n\nfunction getReactNative(): ReactNativeSubset | null {\n if (reactNative !== undefined) {\n return reactNative\n }\n try {\n reactNative = require(\"react-native\") as ReactNativeSubset\n } catch {\n reactNative = null\n }\n return reactNative\n}\n\nfunction isDev(): boolean {\n return typeof __DEV__ !== \"undefined\" && __DEV__\n}\n\ntype NitroTimerApi = {\n setInterval: (callback: () => void, delay: number) => number\n clearInterval: (intervalId: number) => void\n setTimeout: (callback: () => void, delay: number) => number\n clearTimeout: (timeoutId: number) => void\n}\n\nlet nitroTimer: NitroTimerApi | null | undefined\nlet nitroDisabled = false\nlet failedLoud = false\n\n/**\n * The native background timer is unavailable — say so ONCE, loudly, with the\n * remediation. The JS-timer fallback keeps foreground behavior working, but\n * everything timing-driven freezes while the app is backgrounded, which\n * presents as phantom miniapp bugs (frozen captions, missed wake words,\n * watchdog kills on resume). A quiet warning here has already cost a full\n * debugging day; never downgrade this to console.warn.\n */\nfunction failUnavailable(reason: string) {\n if (failedLoud) {\n return\n }\n failedLoud = true\n const message =\n `BgTimer: native background timer unavailable (${reason}). ` +\n \"Backgrounded behavior IS BROKEN until you rebuild the Android app: run `bun android`. \" +\n \"Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded.\"\n console.error(message)\n if (isDev()) {\n // A stale dev client may ALSO show the library's own require-time red box\n // (bridgeless LogBox surfaces it even though we catch below) — this alert\n // is the actionable one: it names the fix.\n try {\n getReactNative()?.Alert?.alert(\"Background timers unavailable\", message)\n } catch {\n /* Alert not available (tests / headless) — the console.error stands. */\n }\n }\n}\n\nfunction getNitroTimer(): NitroTimerApi | null {\n if (nitroDisabled || getReactNative()?.Platform.OS !== \"android\") {\n return null\n }\n\n if (nitroTimer !== undefined) {\n return nitroTimer\n }\n\n try {\n const {isRuntimeAlive} = require(\"react-native-nitro-modules\") as {isRuntimeAlive?: () => boolean}\n if (typeof isRuntimeAlive === \"function\" && !isRuntimeAlive()) {\n nitroTimer = null\n failUnavailable(\"nitro runtime is not alive\")\n return nitroTimer\n }\n\n const {BackgroundTimer} = require(\"react-native-nitro-bg-timer\") as {BackgroundTimer?: NitroTimerApi}\n nitroTimer =\n BackgroundTimer &&\n typeof BackgroundTimer.setTimeout === \"function\" &&\n typeof BackgroundTimer.setInterval === \"function\" &&\n typeof BackgroundTimer.clearTimeout === \"function\" &&\n typeof BackgroundTimer.clearInterval === \"function\"\n ? BackgroundTimer\n : null\n } catch {\n nitroTimer = null\n nitroDisabled = true\n }\n\n if (!nitroTimer) {\n failUnavailable(\"react-native-nitro-bg-timer failed to load\")\n }\n return nitroTimer\n}\n\nfunction withNitro<T>(run: (api: NitroTimerApi) => T, fallback: () => T): T {\n const api = getNitroTimer()\n if (!api) {\n return fallback()\n }\n try {\n return run(api)\n } catch (error) {\n nitroDisabled = true\n nitroTimer = null\n failedLoud = false // a mid-session failure is new information — re-announce\n failUnavailable(`nitro timer call threw: ${String(error)}`)\n return fallback()\n }\n}\n\nexport class BgTimer {\n static setInterval(callback: () => void, delay: number): number {\n return withNitro(\n (api) => api.setInterval(callback, delay),\n () => setInterval(callback, delay) as unknown as number,\n )\n }\n\n static clearInterval(intervalId: number): void {\n withNitro(\n (api) => api.clearInterval(intervalId),\n () => clearInterval(intervalId),\n )\n }\n\n static setTimeout(callback: () => void, delay: number): number {\n return withNitro(\n (api) => api.setTimeout(callback, delay),\n () => setTimeout(callback, delay) as unknown as number,\n )\n }\n\n static clearTimeout(timeoutId: number): void {\n withNitro(\n (api) => api.clearTimeout(timeoutId),\n () => clearTimeout(timeoutId),\n )\n }\n}\n\nexport function throttle<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void {\n let lastCalled = 0\n\n return (...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastCalled >= ms) {\n lastCalled = now\n fn(...args)\n }\n }\n}\n\nexport function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): (...args: Parameters<T>) => void {\n let timeoutId: number | null = null\n\n return (...args: Parameters<T>) => {\n if (timeoutId) {\n BgTimer.clearTimeout(timeoutId)\n }\n timeoutId = BgTimer.setTimeout(() => {\n fn(...args)\n timeoutId = null\n }, ms)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"timers.js","sourceRoot":"","sources":["../../../src/utils/timers/timers.ts"],"names":[],"mappings":"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","sourcesContent":["// BgTimer: every engine timer (miniapp liveness watchdog, display expiries,\n// boot windows, token refresh) goes through here. Android pauses plain JS\n// timers while the app is backgrounded, so on a device these run on the\n// native react-native-nitro-bg-timer instead. iOS needs that package at\n// >= 0.2.0: earlier versions cleared each timer right after scheduling it\n// (https://github.com/tconns/react-native-nitro-bg-timer/issues/2).\n//\n// Dev and release behave the same; there is no env switch. A missing native\n// module falls back to JS timers so the foreground keeps working, and says so\n// once, loudly: a quiet fallback already cost a day of phantom \"zombie\n// miniapp\" bugs (OS-1790). Never downgrade that report to a warning.\n//\n// react-native and the nitro packages are require()d lazily. The engine's bun\n// suites run services in a plain JS runtime that cannot parse react-native;\n// there the native lookup finds no platform and JS timers are the right answer.\n\ntype TimerApi = {\n setTimeout(callback: () => void, delay: number): number\n clearTimeout(id: number): void\n setInterval(callback: () => void, delay: number): number\n clearInterval(id: number): void\n}\n\ntype ReactNativeSubset = {\n Platform: {OS: string}\n Alert?: {alert(title: string, message?: string): void}\n}\n\nconst TIMER_METHODS = [\"setTimeout\", \"clearTimeout\", \"setInterval\", \"clearInterval\"] as const\n\nconst jsTimers: TimerApi = {\n setTimeout: (callback, delay) => setTimeout(callback, delay) as unknown as number,\n clearTimeout: (id) => clearTimeout(id),\n setInterval: (callback, delay) => setInterval(callback, delay) as unknown as number,\n clearInterval: (id) => clearInterval(id),\n}\n\nlet reactNative: ReactNativeSubset | null | undefined\n// undefined = not looked up yet, null = unavailable (JS timers from here on).\nlet nativeTimers: TimerApi | null | undefined\nlet reported = false\n\nfunction loadReactNative(): ReactNativeSubset | null {\n if (reactNative === undefined) {\n try {\n reactNative = require(\"react-native\") as ReactNativeSubset\n } catch {\n reactNative = null\n }\n }\n return reactNative\n}\n\nfunction reportUnavailable(reason: string): void {\n if (reported) return\n reported = true\n const rn = loadReactNative()\n const platform = rn?.Platform.OS === \"ios\" ? \"ios\" : \"android\"\n const message =\n `BgTimer: native background timer unavailable (${reason}). ` +\n `Backgrounded behavior IS BROKEN until you rebuild the app: run \\`bun ${platform}\\`. ` +\n \"Engine timers and local miniapps (captions, wake words) freeze whenever the app is not foregrounded.\"\n console.error(message)\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n // A stale dev client may also red-box inside the library itself; this\n // alert is the one that names the fix.\n try {\n rn?.Alert?.alert(\"Background timers unavailable\", message)\n } catch {\n // Headless runtime: the console.error stands.\n }\n }\n}\n\nfunction loadNativeTimers(): TimerApi | null {\n if (nativeTimers !== undefined) return nativeTimers\n const platform = loadReactNative()?.Platform.OS\n if (platform !== \"android\" && platform !== \"ios\") {\n nativeTimers = null\n return null\n }\n try {\n const {isRuntimeAlive} = require(\"react-native-nitro-modules\") as {isRuntimeAlive?: () => boolean}\n if (typeof isRuntimeAlive === \"function\" && !isRuntimeAlive()) throw new Error(\"nitro runtime is not alive\")\n const {BackgroundTimer} = require(\"react-native-nitro-bg-timer\") as {BackgroundTimer?: Partial<TimerApi>}\n for (const method of TIMER_METHODS) {\n if (typeof BackgroundTimer?.[method] !== \"function\") throw new Error(`BackgroundTimer.${method} missing`)\n }\n nativeTimers = BackgroundTimer as TimerApi\n } catch (error) {\n nativeTimers = null\n reportUnavailable(error instanceof Error ? error.message : String(error))\n }\n return nativeTimers\n}\n\n// A native call that throws mid-session is new information: drop to JS timers\n// and announce again.\nfunction call<T>(run: (timers: TimerApi) => T): T {\n const native = loadNativeTimers()\n if (!native) return run(jsTimers)\n try {\n return run(native)\n } catch (error) {\n nativeTimers = null\n reported = false\n reportUnavailable(`native timer call threw: ${String(error)}`)\n return run(jsTimers)\n }\n}\n\nexport class BgTimer {\n static setTimeout(callback: () => void, delay: number): number {\n return call((timers) => timers.setTimeout(callback, delay))\n }\n\n static clearTimeout(id: number): void {\n call((timers) => timers.clearTimeout(id))\n }\n\n static setInterval(callback: () => void, delay: number): number {\n return call((timers) => timers.setInterval(callback, delay))\n }\n\n static clearInterval(id: number): void {\n call((timers) => timers.clearInterval(id))\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassly/engine",
|
|
3
|
-
"version": "0.3.3-dev.
|
|
3
|
+
"version": "0.3.3-dev.645",
|
|
4
4
|
"description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -97,17 +97,17 @@
|
|
|
97
97
|
"registry": "https://registry.npmjs.org/"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@glassly/bluetooth-sdk": "0.3.3-dev.
|
|
101
|
-
"@glassly/cloud-client": "0.3.3-dev.
|
|
102
|
-
"@glassly/cloud-protocol": "0.3.3-dev.
|
|
103
|
-
"@glassly/crust": "0.3.3-dev.
|
|
104
|
-
"@glassly/miniapp": "0.3.3-dev.
|
|
100
|
+
"@glassly/bluetooth-sdk": "0.3.3-dev.645",
|
|
101
|
+
"@glassly/cloud-client": "0.3.3-dev.645",
|
|
102
|
+
"@glassly/cloud-protocol": "0.3.3-dev.645",
|
|
103
|
+
"@glassly/crust": "0.3.3-dev.645",
|
|
104
|
+
"@glassly/miniapp": "0.3.3-dev.645",
|
|
105
105
|
"buffer": "^6.0.3",
|
|
106
106
|
"events": "^3.3.0",
|
|
107
107
|
"react-native-marked": "8.1.1",
|
|
108
108
|
"semver": "^7.7.4",
|
|
109
109
|
"typesafe-ts": "^1.7.1",
|
|
110
|
-
"@glassly/llm-providers": "0.3.3-dev.
|
|
110
|
+
"@glassly/llm-providers": "0.3.3-dev.645"
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
113
|
"@glassly/llm-providers": "workspace:*",
|
|
@@ -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.3.3",
|
|
15
|
-
"releaseIdentity": "0.3.3-dev.
|
|
16
|
-
"releaseSetId": "glassly-0.3.3-dev.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.3.3-dev.645",
|
|
16
|
+
"releaseSetId": "glassly-0.3.3-dev.645",
|
|
17
|
+
"sourceCommit": "d448896b180f4eb054a597d2c460d6eae8841a64",
|
|
18
18
|
"otaManifestUrl": null,
|
|
19
19
|
"otaManifestSha256": null
|
|
20
20
|
})
|
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,
|
|
@@ -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
|
}
|
|
@@ -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
|
}
|