@ccheever/exact-ibex-runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +63 -0
- package/src/abort/AbortController.ts +23 -0
- package/src/abort/AbortSignal.ts +152 -0
- package/src/abort/index.ts +2 -0
- package/src/accessibility.ts +12 -0
- package/src/arraybuffer-detach.ts +109 -0
- package/src/base64/base64.ts +168 -0
- package/src/base64/index.ts +1 -0
- package/src/blob/Blob.ts +259 -0
- package/src/blob/File.ts +59 -0
- package/src/blob/FormData.ts +323 -0
- package/src/blob/index.ts +3 -0
- package/src/bootstrap.ts +1946 -0
- package/src/broadcast/BroadcastChannel.ts +280 -0
- package/src/broadcast/index.ts +5 -0
- package/src/cache/Cache.ts +349 -0
- package/src/cache/CacheStorage.ts +89 -0
- package/src/cache/index.ts +27 -0
- package/src/camera/index.ts +6202 -0
- package/src/camera/processor.worker.ts +194 -0
- package/src/camera/scene.ts +195 -0
- package/src/clipboard/Clipboard.ts +129 -0
- package/src/clipboard/ClipboardItem.ts +97 -0
- package/src/clipboard/index.ts +6 -0
- package/src/clone/index.ts +1 -0
- package/src/clone/structuredClone.ts +389 -0
- package/src/clone/transferableSymbols.ts +2 -0
- package/src/compression/CompressionStream.ts +146 -0
- package/src/compression/DecompressionStream.ts +342 -0
- package/src/compression/index.ts +4 -0
- package/src/console/Console.ts +341 -0
- package/src/console/index.ts +2 -0
- package/src/core/accessibility-state.ts +263 -0
- package/src/core/accessibility.ts +184 -0
- package/src/core/agent-state.ts +37 -0
- package/src/core/diagnostics-logs.ts +144 -0
- package/src/core/host-call-bridge.ts +16 -0
- package/src/core/i18n-helpers.ts +189 -0
- package/src/core/locale-state.ts +253 -0
- package/src/core/locale.ts +95 -0
- package/src/crypto/Crypto.ts +2743 -0
- package/src/crypto/index.ts +1 -0
- package/src/diagnostics/logs.ts +7 -0
- package/src/encoding/TextDecoder.ts +1181 -0
- package/src/encoding/TextDecoderStream.ts +58 -0
- package/src/encoding/TextEncoder.ts +180 -0
- package/src/encoding/TextEncoderStream.ts +39 -0
- package/src/encoding/index.ts +8 -0
- package/src/events/CloseEvent.ts +91 -0
- package/src/events/DOMException.ts +409 -0
- package/src/events/ErrorEvent.ts +39 -0
- package/src/events/Event.ts +151 -0
- package/src/events/EventTarget.ts +280 -0
- package/src/events/FocusEvent.ts +27 -0
- package/src/events/KeyboardEvent.ts +46 -0
- package/src/events/MessageEvent.ts +61 -0
- package/src/events/ProgressEvent.ts +33 -0
- package/src/events/PromiseRejectionEvent.ts +31 -0
- package/src/events/index.ts +52 -0
- package/src/eventsource/EventSource.ts +371 -0
- package/src/eventsource/index.ts +2 -0
- package/src/fetch/Headers.ts +642 -0
- package/src/fetch/Request.ts +760 -0
- package/src/fetch/Response.ts +543 -0
- package/src/fetch/body.ts +1256 -0
- package/src/fetch/cookie-jar.ts +566 -0
- package/src/fetch/demo.ts +207 -0
- package/src/fetch/errors.ts +101 -0
- package/src/fetch/fetch.ts +2610 -0
- package/src/fetch/index.ts +101 -0
- package/src/fetch/native-bridge.ts +65 -0
- package/src/fetch/types.ts +258 -0
- package/src/filereader/FileReader.ts +236 -0
- package/src/filereader/index.ts +1 -0
- package/src/fs/Dirent.ts +39 -0
- package/src/fs/ExactFile.ts +450 -0
- package/src/fs/Stats.ts +80 -0
- package/src/fs/index.ts +944 -0
- package/src/fs/promises.ts +386 -0
- package/src/fs/shared.ts +328 -0
- package/src/http-server/index.js +697 -0
- package/src/http-server/index.ts +27 -0
- package/src/identity.generated.ts +14 -0
- package/src/index.ts +283 -0
- package/src/indexeddb/IDBCursor.ts +188 -0
- package/src/indexeddb/IDBDatabase.ts +343 -0
- package/src/indexeddb/IDBFactory.ts +269 -0
- package/src/indexeddb/IDBIndex.ts +194 -0
- package/src/indexeddb/IDBKeyRange.ts +109 -0
- package/src/indexeddb/IDBObjectStore.ts +468 -0
- package/src/indexeddb/IDBRequest.ts +163 -0
- package/src/indexeddb/IDBTransaction.ts +207 -0
- package/src/indexeddb/index.ts +34 -0
- package/src/indexeddb/utils.ts +52 -0
- package/src/inspect/index.ts +1 -0
- package/src/inspect/inspect.ts +465 -0
- package/src/internal/detect.ts +104 -0
- package/src/locale.ts +10 -0
- package/src/location/index.ts +1059 -0
- package/src/locks/LockManager.ts +460 -0
- package/src/locks/index.ts +12 -0
- package/src/media/VideoFrame.ts +58 -0
- package/src/messaging/MessageChannel.ts +31 -0
- package/src/messaging/MessagePort.ts +180 -0
- package/src/messaging/index.ts +2 -0
- package/src/messaging.ts +247 -0
- package/src/native/NativeModules.ts +354 -0
- package/src/native/index.ts +1 -0
- package/src/navigator/Navigator.ts +351 -0
- package/src/navigator/index.ts +1 -0
- package/src/node/Buffer.ts +1786 -0
- package/src/node/index.ts +4 -0
- package/src/node/path.ts +495 -0
- package/src/node/process.ts +2528 -0
- package/src/performance/Performance.ts +532 -0
- package/src/performance/index.ts +21 -0
- package/src/polyfills/array.ts +236 -0
- package/src/polyfills/arraybuffer.ts +172 -0
- package/src/polyfills/groupby.ts +85 -0
- package/src/polyfills/index.ts +85 -0
- package/src/polyfills/intl.ts +1956 -0
- package/src/polyfills/iterator.ts +479 -0
- package/src/polyfills/promise.ts +37 -0
- package/src/polyfills/set.ts +245 -0
- package/src/polyfills/string.ts +85 -0
- package/src/polyfills/typedarray.ts +110 -0
- package/src/promise-rejection-tracking.ts +464 -0
- package/src/react-native/index.ts +388 -0
- package/src/runtime-entry.ts +55 -0
- package/src/scheduling/AnimationFrame.ts +105 -0
- package/src/scheduling/IdleCallback.ts +167 -0
- package/src/scheduling/index.ts +13 -0
- package/src/security/Capabilities.ts +1146 -0
- package/src/security/Permissions.ts +392 -0
- package/src/security/capability-bits.generated.ts +63 -0
- package/src/security/index.ts +16 -0
- package/src/sqlite/Database.ts +456 -0
- package/src/sqlite/Statement.ts +206 -0
- package/src/sqlite/constants.ts +79 -0
- package/src/sqlite/errors.ts +25 -0
- package/src/sqlite/index.ts +34 -0
- package/src/sqlite/module.js +438 -0
- package/src/storage/Storage.ts +291 -0
- package/src/storage/StorageManager.ts +91 -0
- package/src/storage/index.ts +3 -0
- package/src/stream-compat.ts +47 -0
- package/src/streams/ReadableStream.ts +4131 -0
- package/src/streams/TransformStream.ts +375 -0
- package/src/streams/WritableStream.ts +866 -0
- package/src/streams/index.ts +41 -0
- package/src/timers/Timers.ts +296 -0
- package/src/timers/index.ts +11 -0
- package/src/url/URL.ts +656 -0
- package/src/url/URLPattern.ts +850 -0
- package/src/url/URLSearchParams.ts +244 -0
- package/src/url/index.ts +9 -0
- package/src/websocket/WebSocket.ts +770 -0
- package/src/websocket/WebSocketError.ts +52 -0
- package/src/websocket/WebSocketStream.ts +628 -0
- package/src/websocket/index.ts +7 -0
- package/src/window/index.ts +872 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// @system @ref LLP 0011#state-modules — startup imports only accessibility state.
|
|
2
|
+
export interface ExactAccessibilitySnapshot {
|
|
3
|
+
readonly prefersReducedMotion: boolean;
|
|
4
|
+
readonly isBoldTextEnabled: boolean;
|
|
5
|
+
readonly prefersHighContrast: boolean;
|
|
6
|
+
readonly prefersReducedTransparency: boolean;
|
|
7
|
+
readonly fontScale: number;
|
|
8
|
+
readonly isScreenReaderEnabled: boolean;
|
|
9
|
+
readonly colorScheme: "light" | "dark";
|
|
10
|
+
readonly isInvertColorsEnabled: boolean;
|
|
11
|
+
readonly isGrayscaleEnabled: boolean;
|
|
12
|
+
readonly dynamicTypeSize: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface NativeAccessibilitySnapshot {
|
|
16
|
+
readonly prefersReducedMotion?: boolean;
|
|
17
|
+
readonly isBoldTextEnabled?: boolean;
|
|
18
|
+
readonly prefersHighContrast?: boolean;
|
|
19
|
+
readonly prefersReducedTransparency?: boolean;
|
|
20
|
+
readonly fontScale?: number;
|
|
21
|
+
readonly isScreenReaderEnabled?: boolean;
|
|
22
|
+
readonly colorScheme?: "light" | "dark";
|
|
23
|
+
readonly isInvertColorsEnabled?: boolean;
|
|
24
|
+
readonly isGrayscaleEnabled?: boolean;
|
|
25
|
+
readonly dynamicTypeSize?: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type AccessibilityInfoKey = keyof ExactAccessibilitySnapshot;
|
|
29
|
+
export type AccessibilityInfoEvent =
|
|
30
|
+
| "change"
|
|
31
|
+
| "reduceMotionChanged"
|
|
32
|
+
| "boldTextChanged"
|
|
33
|
+
| "highContrastChanged"
|
|
34
|
+
| "reducedTransparencyChanged"
|
|
35
|
+
| "fontScaleChanged"
|
|
36
|
+
| "screenReaderChanged"
|
|
37
|
+
| "colorSchemeChanged"
|
|
38
|
+
| "invertColorsChanged"
|
|
39
|
+
| "grayscaleChanged"
|
|
40
|
+
| "dynamicTypeSizeChanged";
|
|
41
|
+
|
|
42
|
+
export type ExactAccessibilityListener = (snapshot: ExactAccessibilitySnapshot) => void;
|
|
43
|
+
export type AccessibilityEventListener = (value: unknown) => void;
|
|
44
|
+
|
|
45
|
+
interface ExactAccessibilityRuntimeState {
|
|
46
|
+
snapshot: ExactAccessibilitySnapshot;
|
|
47
|
+
listeners: Set<ExactAccessibilityListener>;
|
|
48
|
+
eventListeners: Map<AccessibilityInfoEvent, Set<AccessibilityEventListener>>;
|
|
49
|
+
changeTimer: ReturnType<typeof setTimeout> | null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare global {
|
|
53
|
+
// eslint-disable-next-line no-var
|
|
54
|
+
var __exactAccessibilityState: ExactAccessibilityRuntimeState | undefined;
|
|
55
|
+
// eslint-disable-next-line no-var
|
|
56
|
+
var __exactAccessibilitySnapshot: NativeAccessibilitySnapshot | undefined;
|
|
57
|
+
// eslint-disable-next-line no-var
|
|
58
|
+
var __exactAccessibilityChanged:
|
|
59
|
+
| ((snapshot?: NativeAccessibilitySnapshot | null) => void)
|
|
60
|
+
| undefined;
|
|
61
|
+
// eslint-disable-next-line no-var
|
|
62
|
+
var __exactAppearanceState:
|
|
63
|
+
| {
|
|
64
|
+
colorScheme?: "light" | "dark";
|
|
65
|
+
reducedMotion?: boolean;
|
|
66
|
+
}
|
|
67
|
+
| undefined;
|
|
68
|
+
// eslint-disable-next-line no-var
|
|
69
|
+
var __exactWindowNotifyMediaChange:
|
|
70
|
+
| ((next: { colorScheme?: "light" | "dark"; reducedMotion?: boolean }) => void)
|
|
71
|
+
| undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function freezeSnapshot(snapshot: ExactAccessibilitySnapshot): ExactAccessibilitySnapshot {
|
|
75
|
+
return Object.freeze({ ...snapshot });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizeFontScale(value: unknown): number {
|
|
79
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function readNativeAccessibilitySnapshot(): NativeAccessibilitySnapshot | null {
|
|
83
|
+
const nativeSnapshot = globalThis.__exactAccessibilitySnapshot;
|
|
84
|
+
if (nativeSnapshot && typeof nativeSnapshot === "object") {
|
|
85
|
+
return nativeSnapshot;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const appearanceState = globalThis.__exactAppearanceState;
|
|
89
|
+
if (appearanceState && typeof appearanceState === "object") {
|
|
90
|
+
return {
|
|
91
|
+
colorScheme: appearanceState.colorScheme === "dark" ? "dark" : "light",
|
|
92
|
+
prefersReducedMotion: appearanceState.reducedMotion === true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function buildAccessibilitySnapshot(
|
|
100
|
+
value: NativeAccessibilitySnapshot | null,
|
|
101
|
+
): ExactAccessibilitySnapshot {
|
|
102
|
+
return freezeSnapshot({
|
|
103
|
+
prefersReducedMotion: value?.prefersReducedMotion === true,
|
|
104
|
+
isBoldTextEnabled: value?.isBoldTextEnabled === true,
|
|
105
|
+
prefersHighContrast: value?.prefersHighContrast === true,
|
|
106
|
+
prefersReducedTransparency: value?.prefersReducedTransparency === true,
|
|
107
|
+
fontScale: normalizeFontScale(value?.fontScale),
|
|
108
|
+
isScreenReaderEnabled: value?.isScreenReaderEnabled === true,
|
|
109
|
+
colorScheme: value?.colorScheme === "dark" ? "dark" : "light",
|
|
110
|
+
isInvertColorsEnabled: value?.isInvertColorsEnabled === true,
|
|
111
|
+
isGrayscaleEnabled: value?.isGrayscaleEnabled === true,
|
|
112
|
+
dynamicTypeSize:
|
|
113
|
+
typeof value?.dynamicTypeSize === "string" && value.dynamicTypeSize.length > 0
|
|
114
|
+
? value.dynamicTypeSize
|
|
115
|
+
: null,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function createDefaultState(): ExactAccessibilityRuntimeState {
|
|
120
|
+
return {
|
|
121
|
+
snapshot: buildAccessibilitySnapshot(readNativeAccessibilitySnapshot()),
|
|
122
|
+
listeners: new Set(),
|
|
123
|
+
eventListeners: new Map(),
|
|
124
|
+
changeTimer: null,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getAccessibilityState(): ExactAccessibilityRuntimeState {
|
|
129
|
+
if (!globalThis.__exactAccessibilityState) {
|
|
130
|
+
globalThis.__exactAccessibilityState = createDefaultState();
|
|
131
|
+
}
|
|
132
|
+
return globalThis.__exactAccessibilityState;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function dispatchAccessibilityChange(state: ExactAccessibilityRuntimeState): void {
|
|
136
|
+
const snapshot = state.snapshot;
|
|
137
|
+
for (const listener of state.listeners) {
|
|
138
|
+
try {
|
|
139
|
+
listener(snapshot);
|
|
140
|
+
} catch {
|
|
141
|
+
// Ignore listener failures.
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function emitNamedEvent(
|
|
147
|
+
state: ExactAccessibilityRuntimeState,
|
|
148
|
+
event: AccessibilityInfoEvent,
|
|
149
|
+
value: unknown,
|
|
150
|
+
): void {
|
|
151
|
+
const listeners = state.eventListeners.get(event);
|
|
152
|
+
if (!listeners) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
for (const listener of listeners) {
|
|
157
|
+
try {
|
|
158
|
+
listener(value);
|
|
159
|
+
} catch {
|
|
160
|
+
// Ignore listener failures.
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function scheduleAccessibilityChange(state: ExactAccessibilityRuntimeState): void {
|
|
166
|
+
if (state.changeTimer != null) {
|
|
167
|
+
clearTimeout(state.changeTimer);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
state.changeTimer = setTimeout(() => {
|
|
171
|
+
state.changeTimer = null;
|
|
172
|
+
dispatchAccessibilityChange(state);
|
|
173
|
+
}, 100);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function updateAppearanceMirror(snapshot: ExactAccessibilitySnapshot): void {
|
|
177
|
+
globalThis.__exactAppearanceState = {
|
|
178
|
+
colorScheme: snapshot.colorScheme,
|
|
179
|
+
reducedMotion: snapshot.prefersReducedMotion,
|
|
180
|
+
};
|
|
181
|
+
globalThis.__exactWindowNotifyMediaChange?.({
|
|
182
|
+
colorScheme: snapshot.colorScheme,
|
|
183
|
+
reducedMotion: snapshot.prefersReducedMotion,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function updateAccessibilitySnapshot(
|
|
188
|
+
value: NativeAccessibilitySnapshot | null,
|
|
189
|
+
notify: boolean,
|
|
190
|
+
): ExactAccessibilitySnapshot {
|
|
191
|
+
const state = getAccessibilityState();
|
|
192
|
+
const previous = state.snapshot;
|
|
193
|
+
const next = buildAccessibilitySnapshot(value);
|
|
194
|
+
state.snapshot = next;
|
|
195
|
+
updateAppearanceMirror(next);
|
|
196
|
+
|
|
197
|
+
const changedEntries = ([
|
|
198
|
+
["prefersReducedMotion", "reduceMotionChanged"],
|
|
199
|
+
["isBoldTextEnabled", "boldTextChanged"],
|
|
200
|
+
["prefersHighContrast", "highContrastChanged"],
|
|
201
|
+
["prefersReducedTransparency", "reducedTransparencyChanged"],
|
|
202
|
+
["fontScale", "fontScaleChanged"],
|
|
203
|
+
["isScreenReaderEnabled", "screenReaderChanged"],
|
|
204
|
+
["colorScheme", "colorSchemeChanged"],
|
|
205
|
+
["isInvertColorsEnabled", "invertColorsChanged"],
|
|
206
|
+
["isGrayscaleEnabled", "grayscaleChanged"],
|
|
207
|
+
["dynamicTypeSize", "dynamicTypeSizeChanged"],
|
|
208
|
+
] as const).filter(([key]) => previous[key] !== next[key]);
|
|
209
|
+
|
|
210
|
+
if (notify && changedEntries.length > 0) {
|
|
211
|
+
scheduleAccessibilityChange(state);
|
|
212
|
+
for (const [key, event] of changedEntries) {
|
|
213
|
+
emitNamedEvent(state, event, next[key]);
|
|
214
|
+
}
|
|
215
|
+
emitNamedEvent(state, "change", next);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return next;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function subscribeExactAccessibilityChanges(
|
|
222
|
+
listener: ExactAccessibilityListener,
|
|
223
|
+
): () => void {
|
|
224
|
+
const state = getAccessibilityState();
|
|
225
|
+
state.listeners.add(listener);
|
|
226
|
+
return () => {
|
|
227
|
+
state.listeners.delete(listener);
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function addExactAccessibilityEventListener(
|
|
232
|
+
event: AccessibilityInfoEvent,
|
|
233
|
+
listener: AccessibilityEventListener,
|
|
234
|
+
): () => void {
|
|
235
|
+
const state = getAccessibilityState();
|
|
236
|
+
const listeners = state.eventListeners.get(event) ?? new Set<AccessibilityEventListener>();
|
|
237
|
+
listeners.add(listener);
|
|
238
|
+
state.eventListeners.set(event, listeners);
|
|
239
|
+
return () => {
|
|
240
|
+
listeners.delete(listener);
|
|
241
|
+
if (listeners.size === 0) {
|
|
242
|
+
state.eventListeners.delete(event);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function getExactAccessibilitySnapshot(): ExactAccessibilitySnapshot {
|
|
248
|
+
return getAccessibilityState().snapshot;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function refreshExactAccessibility(): ExactAccessibilitySnapshot {
|
|
252
|
+
return updateAccessibilitySnapshot(readNativeAccessibilitySnapshot(), true);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function _resetExactAccessibilityForTests(): void {
|
|
256
|
+
const state = globalThis.__exactAccessibilityState;
|
|
257
|
+
if (state?.changeTimer != null) {
|
|
258
|
+
clearTimeout(state.changeTimer);
|
|
259
|
+
}
|
|
260
|
+
delete globalThis.__exactAccessibilityState;
|
|
261
|
+
delete globalThis.__exactAccessibilityChanged;
|
|
262
|
+
delete globalThis.__exactAccessibilitySnapshot;
|
|
263
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// @system @ref LLP 0011#state-modules — accessibility preferences in shared runtime state.
|
|
2
|
+
import { hostCallBridge } from "./host-call-bridge.js";
|
|
3
|
+
import {
|
|
4
|
+
addExactAccessibilityEventListener,
|
|
5
|
+
getExactAccessibilitySnapshot,
|
|
6
|
+
readNativeAccessibilitySnapshot,
|
|
7
|
+
subscribeExactAccessibilityChanges,
|
|
8
|
+
updateAccessibilitySnapshot,
|
|
9
|
+
type AccessibilityEventListener,
|
|
10
|
+
type AccessibilityInfoEvent,
|
|
11
|
+
type AccessibilityInfoKey,
|
|
12
|
+
type ExactAccessibilitySnapshot,
|
|
13
|
+
type NativeAccessibilitySnapshot,
|
|
14
|
+
} from "./accessibility-state.js";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
_resetExactAccessibilityForTests,
|
|
18
|
+
getExactAccessibilitySnapshot,
|
|
19
|
+
refreshExactAccessibility,
|
|
20
|
+
subscribeExactAccessibilityChanges,
|
|
21
|
+
type AccessibilityInfoEvent,
|
|
22
|
+
type AccessibilityInfoKey,
|
|
23
|
+
type ExactAccessibilitySnapshot,
|
|
24
|
+
} from "./accessibility-state.js";
|
|
25
|
+
|
|
26
|
+
interface ExactAccessibilityNamespace {
|
|
27
|
+
readonly prefersReducedMotion: boolean;
|
|
28
|
+
readonly isBoldTextEnabled: boolean;
|
|
29
|
+
readonly prefersHighContrast: boolean;
|
|
30
|
+
readonly prefersReducedTransparency: boolean;
|
|
31
|
+
readonly fontScale: number;
|
|
32
|
+
readonly isScreenReaderEnabled: boolean;
|
|
33
|
+
readonly colorScheme: "light" | "dark";
|
|
34
|
+
readonly isInvertColorsEnabled: boolean;
|
|
35
|
+
readonly isGrayscaleEnabled: boolean;
|
|
36
|
+
readonly dynamicTypeSize: string | null;
|
|
37
|
+
get<K extends AccessibilityInfoKey>(key: K): ExactAccessibilitySnapshot[K];
|
|
38
|
+
addEventListener(event: AccessibilityInfoEvent, listener: AccessibilityEventListener): () => void;
|
|
39
|
+
announce(message: string, options?: { queue?: boolean }): boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function createAccessibilityNamespace(): ExactAccessibilityNamespace {
|
|
43
|
+
return {
|
|
44
|
+
get prefersReducedMotion() {
|
|
45
|
+
return getExactAccessibilitySnapshot().prefersReducedMotion;
|
|
46
|
+
},
|
|
47
|
+
get isBoldTextEnabled() {
|
|
48
|
+
return getExactAccessibilitySnapshot().isBoldTextEnabled;
|
|
49
|
+
},
|
|
50
|
+
get prefersHighContrast() {
|
|
51
|
+
return getExactAccessibilitySnapshot().prefersHighContrast;
|
|
52
|
+
},
|
|
53
|
+
get prefersReducedTransparency() {
|
|
54
|
+
return getExactAccessibilitySnapshot().prefersReducedTransparency;
|
|
55
|
+
},
|
|
56
|
+
get fontScale() {
|
|
57
|
+
return getExactAccessibilitySnapshot().fontScale;
|
|
58
|
+
},
|
|
59
|
+
get isScreenReaderEnabled() {
|
|
60
|
+
return getExactAccessibilitySnapshot().isScreenReaderEnabled;
|
|
61
|
+
},
|
|
62
|
+
get colorScheme() {
|
|
63
|
+
return getExactAccessibilitySnapshot().colorScheme;
|
|
64
|
+
},
|
|
65
|
+
get isInvertColorsEnabled() {
|
|
66
|
+
return getExactAccessibilitySnapshot().isInvertColorsEnabled;
|
|
67
|
+
},
|
|
68
|
+
get isGrayscaleEnabled() {
|
|
69
|
+
return getExactAccessibilitySnapshot().isGrayscaleEnabled;
|
|
70
|
+
},
|
|
71
|
+
get dynamicTypeSize() {
|
|
72
|
+
return getExactAccessibilitySnapshot().dynamicTypeSize;
|
|
73
|
+
},
|
|
74
|
+
get(key) {
|
|
75
|
+
return getExactAccessibilitySnapshot()[key];
|
|
76
|
+
},
|
|
77
|
+
addEventListener(event, listener) {
|
|
78
|
+
return addExactAccessibilityEventListener(event, listener);
|
|
79
|
+
},
|
|
80
|
+
announce(message, options) {
|
|
81
|
+
return announceForAccessibility(message, options);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function installExactAccessibilityGlobal(): ExactAccessibilityNamespace {
|
|
87
|
+
const g = globalThis as typeof globalThis & {
|
|
88
|
+
Exact?: Record<string, unknown>;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (typeof g.Exact !== "object" || g.Exact === null) {
|
|
92
|
+
g.Exact = {};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const exact = g.Exact as Record<string, unknown>;
|
|
96
|
+
const existing = exact.accessibility;
|
|
97
|
+
if (
|
|
98
|
+
existing &&
|
|
99
|
+
typeof existing === "object" &&
|
|
100
|
+
typeof (existing as ExactAccessibilityNamespace).addEventListener === "function"
|
|
101
|
+
) {
|
|
102
|
+
return existing as ExactAccessibilityNamespace;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
updateAccessibilitySnapshot(readNativeAccessibilitySnapshot(), false);
|
|
106
|
+
|
|
107
|
+
const accessibility = createAccessibilityNamespace();
|
|
108
|
+
Object.defineProperty(exact, "accessibility", {
|
|
109
|
+
value: accessibility,
|
|
110
|
+
writable: true,
|
|
111
|
+
configurable: true,
|
|
112
|
+
enumerable: true,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
globalThis.__exactAccessibilityChanged = (snapshot?: NativeAccessibilitySnapshot | null) => {
|
|
116
|
+
if (snapshot && typeof snapshot === "object") {
|
|
117
|
+
globalThis.__exactAccessibilitySnapshot = snapshot;
|
|
118
|
+
}
|
|
119
|
+
updateAccessibilitySnapshot(snapshot ?? readNativeAccessibilitySnapshot(), true);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return accessibility;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function announceForAccessibility(
|
|
126
|
+
message: string,
|
|
127
|
+
options: { queue?: boolean } = {},
|
|
128
|
+
): boolean {
|
|
129
|
+
if (typeof message !== "string" || message.trim().length === 0) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const hostCall = hostCallBridge();
|
|
134
|
+
if (!hostCall) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const result = hostCall(
|
|
140
|
+
"accessibility.announce",
|
|
141
|
+
JSON.stringify({
|
|
142
|
+
message,
|
|
143
|
+
queue: options.queue !== false,
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
return result !== false;
|
|
147
|
+
} catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function focusElementForAccessibility(
|
|
153
|
+
target:
|
|
154
|
+
| { readonly viewId: number }
|
|
155
|
+
| { readonly nativeID: string }
|
|
156
|
+
| { readonly testId: string },
|
|
157
|
+
): boolean {
|
|
158
|
+
const hostCall = hostCallBridge();
|
|
159
|
+
if (!hostCall) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const result = hostCall("accessibility.focus", JSON.stringify(target));
|
|
165
|
+
return result !== false;
|
|
166
|
+
} catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const AccessibilityInfo = {
|
|
172
|
+
get<K extends AccessibilityInfoKey>(key: K): ExactAccessibilitySnapshot[K] {
|
|
173
|
+
return getExactAccessibilitySnapshot()[key];
|
|
174
|
+
},
|
|
175
|
+
addEventListener(
|
|
176
|
+
event: AccessibilityInfoEvent,
|
|
177
|
+
listener: AccessibilityEventListener,
|
|
178
|
+
): () => void {
|
|
179
|
+
return addExactAccessibilityEventListener(event, listener);
|
|
180
|
+
},
|
|
181
|
+
announce(message: string, options?: { queue?: boolean }): boolean {
|
|
182
|
+
return announceForAccessibility(message, options);
|
|
183
|
+
},
|
|
184
|
+
} as const;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const activeAnimationFrames = new Set<number>();
|
|
2
|
+
let lastAnimationActivityAt = 0;
|
|
3
|
+
|
|
4
|
+
function currentTimestamp(): number {
|
|
5
|
+
return Date.now();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function trackAnimationFrameRequested(id: number): void {
|
|
9
|
+
activeAnimationFrames.add(id);
|
|
10
|
+
lastAnimationActivityAt = currentTimestamp();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function trackAnimationFrameCancelled(id: number): void {
|
|
14
|
+
if (activeAnimationFrames.delete(id)) {
|
|
15
|
+
lastAnimationActivityAt = currentTimestamp();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function trackAnimationFrameExecuted(ids: number[]): void {
|
|
20
|
+
let changed = false;
|
|
21
|
+
for (const id of ids) {
|
|
22
|
+
changed = activeAnimationFrames.delete(id) || changed;
|
|
23
|
+
}
|
|
24
|
+
if (changed) {
|
|
25
|
+
lastAnimationActivityAt = currentTimestamp();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getAnimationTrackingState(): {
|
|
30
|
+
activeCount: number;
|
|
31
|
+
lastActivityAt: number;
|
|
32
|
+
} {
|
|
33
|
+
return {
|
|
34
|
+
activeCount: activeAnimationFrames.size,
|
|
35
|
+
lastActivityAt: lastAnimationActivityAt,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export type AgentLogLevel = "debug" | "info" | "warn" | "error" | string;
|
|
2
|
+
export type AgentLogSource = "runtime" | "renderer" | "host" | "agent" | string;
|
|
3
|
+
|
|
4
|
+
export interface AgentLogEntry {
|
|
5
|
+
entryId: string;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
source: AgentLogSource;
|
|
8
|
+
level: AgentLogLevel;
|
|
9
|
+
message: string;
|
|
10
|
+
stack?: string;
|
|
11
|
+
componentStack?: string;
|
|
12
|
+
context?: Record<string, unknown>;
|
|
13
|
+
rootId?: number;
|
|
14
|
+
snapshotId?: string;
|
|
15
|
+
count: number;
|
|
16
|
+
firstTimestamp: number;
|
|
17
|
+
lastTimestamp: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MAX_AGENT_LOG_ENTRIES = 1000;
|
|
21
|
+
const DEDUP_WINDOW_MS = 1000;
|
|
22
|
+
|
|
23
|
+
type AgentLogListener = (entry: AgentLogEntry) => void;
|
|
24
|
+
|
|
25
|
+
export interface AgentLogInput {
|
|
26
|
+
source: AgentLogSource;
|
|
27
|
+
level: AgentLogLevel;
|
|
28
|
+
message: string;
|
|
29
|
+
stack?: string;
|
|
30
|
+
componentStack?: string;
|
|
31
|
+
context?: Record<string, unknown>;
|
|
32
|
+
rootId?: number;
|
|
33
|
+
snapshotId?: string;
|
|
34
|
+
timestamp?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const entries: AgentLogEntry[] = [];
|
|
38
|
+
const listeners = new Set<AgentLogListener>();
|
|
39
|
+
let nextEntryId = 1;
|
|
40
|
+
|
|
41
|
+
function currentTimestamp(): number {
|
|
42
|
+
return Date.now();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function cloneContext(
|
|
46
|
+
context: Record<string, unknown> | undefined,
|
|
47
|
+
): Record<string, unknown> | undefined {
|
|
48
|
+
if (!context) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return { ...context };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function canCollapse(
|
|
55
|
+
previous: AgentLogEntry | undefined,
|
|
56
|
+
next: AgentLogInput,
|
|
57
|
+
timestamp: number,
|
|
58
|
+
): previous is AgentLogEntry {
|
|
59
|
+
if (!previous) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (timestamp - previous.lastTimestamp > DEDUP_WINDOW_MS) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
previous.source === next.source &&
|
|
69
|
+
previous.level === next.level &&
|
|
70
|
+
previous.message === next.message &&
|
|
71
|
+
previous.stack === next.stack &&
|
|
72
|
+
previous.componentStack === next.componentStack &&
|
|
73
|
+
previous.rootId === next.rootId
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function recordAgentLog(
|
|
78
|
+
input: AgentLogInput,
|
|
79
|
+
): { entry: AgentLogEntry; created: boolean } {
|
|
80
|
+
const timestamp = input.timestamp ?? currentTimestamp();
|
|
81
|
+
const previous = entries.length > 0 ? entries[entries.length - 1] : undefined;
|
|
82
|
+
|
|
83
|
+
if (canCollapse(previous, input, timestamp)) {
|
|
84
|
+
previous.count += 1;
|
|
85
|
+
previous.lastTimestamp = timestamp;
|
|
86
|
+
previous.timestamp = timestamp;
|
|
87
|
+
if (input.snapshotId) {
|
|
88
|
+
previous.snapshotId = input.snapshotId;
|
|
89
|
+
}
|
|
90
|
+
if (input.context) {
|
|
91
|
+
previous.context = cloneContext(input.context);
|
|
92
|
+
}
|
|
93
|
+
return { entry: previous, created: false };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const entry: AgentLogEntry = {
|
|
97
|
+
entryId: String(nextEntryId),
|
|
98
|
+
timestamp,
|
|
99
|
+
source: input.source,
|
|
100
|
+
level: input.level,
|
|
101
|
+
message: input.message,
|
|
102
|
+
stack: input.stack,
|
|
103
|
+
componentStack: input.componentStack,
|
|
104
|
+
context: cloneContext(input.context),
|
|
105
|
+
rootId: input.rootId,
|
|
106
|
+
snapshotId: input.snapshotId,
|
|
107
|
+
count: 1,
|
|
108
|
+
firstTimestamp: timestamp,
|
|
109
|
+
lastTimestamp: timestamp,
|
|
110
|
+
};
|
|
111
|
+
nextEntryId += 1;
|
|
112
|
+
|
|
113
|
+
entries.push(entry);
|
|
114
|
+
if (entries.length > MAX_AGENT_LOG_ENTRIES) {
|
|
115
|
+
entries.shift();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (const listener of listeners) {
|
|
119
|
+
try {
|
|
120
|
+
listener(entry);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error("[AgentLogs] listener failed:", error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { entry, created: true };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function getAgentLogEntries(): AgentLogEntry[] {
|
|
130
|
+
return entries.slice();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function subscribeAgentLogs(listener: AgentLogListener): () => void {
|
|
134
|
+
listeners.add(listener);
|
|
135
|
+
return () => {
|
|
136
|
+
listeners.delete(listener);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function _resetAgentLogState(): void {
|
|
141
|
+
entries.length = 0;
|
|
142
|
+
listeners.clear();
|
|
143
|
+
nextEntryId = 1;
|
|
144
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper for looking up the host bridge function exposed on
|
|
3
|
+
* `globalThis.__hostCall`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function hostCallBridge():
|
|
7
|
+
| ((operation: string, argsJson: string) => unknown)
|
|
8
|
+
| null {
|
|
9
|
+
const hostCall = (
|
|
10
|
+
globalThis as {
|
|
11
|
+
__hostCall?: ((operation: string, argsJson: string) => unknown) | undefined;
|
|
12
|
+
}
|
|
13
|
+
).__hostCall;
|
|
14
|
+
|
|
15
|
+
return typeof hostCall === 'function' ? hostCall : null;
|
|
16
|
+
}
|