@flighthq/device 0.5.0-next.1944.cd6b6e7 → 0.5.1-edge.638.d4dbd4e

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/README.md CHANGED
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/device`. The `@fligh
13
13
  This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
14
14
 
15
15
  - [Flight project](https://github.com/flighthq/flight)
16
- - [Source for @flighthq/device@0.5.0-next.1944.cd6b6e7](https://github.com/flighthq/flight/tree/cd6b6e71eb472b3a4249830a7743333f019fa7b7/packages/device)
17
- - [License](https://github.com/flighthq/flight/blob/cd6b6e71eb472b3a4249830a7743333f019fa7b7/LICENSE.md)
16
+ - [Source for @flighthq/device@0.5.1-edge.638.d4dbd4e](https://github.com/flighthq/flight/tree/d4dbd4e347dc8be10b180c85a766ab50333dcb51/packages/device)
17
+ - [License](https://github.com/flighthq/flight/blob/d4dbd4e347dc8be10b180c85a766ab50333dcb51/LICENSE.md)
package/dist/device.d.ts CHANGED
@@ -1,20 +1,12 @@
1
- import type { BackendExplanation, DeviceBackend, DeviceCapabilities, DeviceDisplayMetrics, DeviceInfo, SafeAreaInsets } from '@flighthq/types/contract';
1
+ import type { DeviceCapabilities, DeviceDisplayMetrics, DeviceInfo, HasSystemDevice, SafeAreaInsets } from '@flighthq/types/contract';
2
2
  export declare function createDeviceCapabilities(): DeviceCapabilities;
3
3
  export declare function createDeviceDisplayMetrics(): DeviceDisplayMetrics;
4
4
  export declare function createDeviceInfo(): DeviceInfo;
5
5
  export declare function createSafeAreaInsets(): SafeAreaInsets;
6
- export declare function createWebDeviceBackend(): DeviceBackend;
7
- export declare function enableWebSafeAreaInsets(): () => void;
8
- export declare function explainDeviceBackend(): BackendExplanation;
9
- export declare function getDeviceBackend(): DeviceBackend;
10
- export declare function getDeviceCapabilities(out: DeviceCapabilities): DeviceCapabilities;
11
- export declare function getDeviceDisplayMetrics(out: DeviceDisplayMetrics): DeviceDisplayMetrics;
12
- export declare function getDeviceId(): string;
13
- export declare function getDeviceInfo(out: DeviceInfo): DeviceInfo;
14
- export declare function getSafeAreaInsets(out: SafeAreaInsets): SafeAreaInsets;
15
- export declare function installDeviceHostBackend(backend: DeviceBackend): void;
16
- export declare function observeDeviceHostResult(operation: string, succeeded: boolean): void;
17
- export declare function refreshDeviceInfo(): void;
18
- export declare function resetDeviceBackendForTest(): void;
19
- export declare function setDeviceBackend(backend: DeviceBackend | null): void;
6
+ export declare function getDeviceCapabilities(host: HasSystemDevice, out: DeviceCapabilities): DeviceCapabilities;
7
+ export declare function getDeviceDisplayMetrics(host: HasSystemDevice, out: DeviceDisplayMetrics): DeviceDisplayMetrics;
8
+ export declare function getDeviceId(host: HasSystemDevice): string;
9
+ export declare function getDeviceInfo(host: HasSystemDevice, out: DeviceInfo): DeviceInfo;
10
+ export declare function getSafeAreaInsets(host: HasSystemDevice, out: SafeAreaInsets): SafeAreaInsets;
11
+ export declare function refreshDeviceInfo(host: HasSystemDevice): void;
20
12
  //# sourceMappingURL=device.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACf,MAAM,0BAA0B,CAAC;AASlC,wBAAgB,wBAAwB,IAAI,kBAAkB,CAM7D;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,CAUjE;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CA4B7C;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAID,wBAAgB,sBAAsB,IAAI,aAAa,CA2GtD;AAED,wBAAgB,uBAAuB,IAAI,MAAM,IAAI,CA8BpD;AAED,wBAAgB,oBAAoB,IAAI,kBAAkB,CAazD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,kBAAkB,GAAG,kBAAkB,CAEjF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,oBAAoB,GAAG,oBAAoB,CAEvF;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAEzD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,cAAc,CAErE;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAMrE;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAKnF;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAMxC;AAED,wBAAgB,yBAAyB,IAAI,IAAI,CAKhD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CAEpE"}
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,cAAc,EACf,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,wBAAwB,IAAI,kBAAkB,CAM7D;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,CAUjE;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CA4B7C;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,kBAAkB,GAAG,kBAAkB,CAExG;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,oBAAoB,GAAG,oBAAoB,CAE9G;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAEhF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,cAAc,CAE5F;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAM7D"}
package/dist/device.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { DeviceFormFactorUnknown } from '@flighthq/types/contract';
2
- import { parseUserAgentArch, parseUserAgentFormFactor, parseUserAgentOsName, parseUserAgentOsVersion, } from '@flighthq/useragent/contract';
3
2
  export function createDeviceCapabilities() {
4
3
  return {
5
4
  hasKeyboard: false,
@@ -50,319 +49,26 @@ export function createDeviceInfo() {
50
49
  export function createSafeAreaInsets() {
51
50
  return { bottom: 0, left: 0, right: 0, top: 0 };
52
51
  }
53
- // Builds the default web backend. Reads what the browser exposes and returns sentinels for
54
- // everything a web page cannot know (model/manufacturer, OS version, safe area, DPI).
55
- export function createWebDeviceBackend() {
56
- return {
57
- getCapabilities(out) {
58
- const nav = typeof navigator !== 'undefined' ? navigator : null;
59
- // hasMouse: weak heuristic — no touch points is a strong desktop / pointer-device signal.
60
- // This is best-effort; the browser cannot confirm whether a physical mouse is attached.
61
- const maxTouch = nav !== null && 'maxTouchPoints' in nav ? nav.maxTouchPoints : -1;
62
- out.hasMouse = maxTouch === 0;
63
- // hasKeyboard: desktop UAs very likely have a physical keyboard; mobile UAs likely do not.
64
- // Cannot distinguish virtual + physical keyboard on hybrid devices (Surface, iPad with keyboard).
65
- const ua = nav?.userAgent ?? '';
66
- out.hasKeyboard = detectDesktopUa(ua);
67
- // hasStylus: no reliable UA or API signal in browsers — always false.
68
- out.hasStylus = false;
69
- return out;
70
- },
71
- getDisplayMetrics(out) {
72
- const win = typeof window !== 'undefined' ? window : null;
73
- const scr = typeof screen !== 'undefined' ? screen : null;
74
- out.colorDepth = scr !== null ? scr.colorDepth : -1;
75
- // DPI is not exposed by browsers — always sentinel.
76
- out.densityDpi = -1;
77
- out.logicalHeight = scr !== null ? scr.height : -1;
78
- out.logicalWidth = scr !== null ? scr.width : -1;
79
- const pixelRatio = win !== null ? win.devicePixelRatio : -1;
80
- out.pixelRatio = pixelRatio;
81
- out.physicalWidth = scr !== null && pixelRatio > 0 ? Math.round(scr.width * pixelRatio) : -1;
82
- out.physicalHeight = scr !== null && pixelRatio > 0 ? Math.round(scr.height * pixelRatio) : -1;
83
- return out;
84
- },
85
- getId() {
86
- // Web: crypto.randomUUID() persisted to localStorage as a stable install id.
87
- // Returns '' when storage is unavailable (SSR, private browsing with blocked storage).
88
- // This is an install id — it resets if localStorage is cleared. Not a hardware serial.
89
- // For a durable cross-storage id, use @flighthq/storage as the backend's persistence layer.
90
- try {
91
- const key = '__flighthq_device_id';
92
- const existing = typeof localStorage !== 'undefined' ? localStorage.getItem(key) : null;
93
- if (existing !== null)
94
- return existing;
95
- if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function')
96
- return '';
97
- const id = crypto.randomUUID();
98
- if (typeof localStorage !== 'undefined')
99
- localStorage.setItem(key, id);
100
- return id;
101
- }
102
- catch {
103
- return '';
104
- }
105
- },
106
- getInfo(out) {
107
- const nav = typeof navigator !== 'undefined' ? navigator : null;
108
- const ua = nav?.userAgent ?? '';
109
- const uadPlatform = nav?.userAgentData
110
- ?.platform;
111
- out.arch = parseUserAgentArch(ua, uadPlatform);
112
- // availableMemory is not exposed by browsers — always -1.
113
- out.availableMemory = -1;
114
- // boardName, marketingName, productName, supportedAbis — not exposed by browsers.
115
- out.boardName = '';
116
- out.colorGamut = detectColorGamut();
117
- const cores = nav !== null && 'hardwareConcurrency' in nav ? (nav.hardwareConcurrency ?? -1) : -1;
118
- out.cpuCores = cores;
119
- out.fontScale = -1;
120
- out.formFactor = parseUserAgentFormFactor(ua, nav !== null && 'maxTouchPoints' in nav ? nav.maxTouchPoints : -1);
121
- const gpuInfo = readWebGpuInfo();
122
- out.gpuRenderer = gpuInfo.renderer;
123
- out.gpuVendor = gpuInfo.vendor;
124
- out.isHdr = detectHdr();
125
- // isJailbroken and isRooted are always false on web — no detection available.
126
- out.isJailbroken = false;
127
- const devMem = nav !== null && 'deviceMemory' in nav ? (nav.deviceMemory ?? -1) : -1;
128
- out.isLowEndDevice = detectLowEndDevice(devMem, cores);
129
- out.isRooted = false;
130
- out.isVirtual = false;
131
- out.manufacturer = '';
132
- out.marketingName = '';
133
- out.model = '';
134
- out.osBuild = '';
135
- out.osName = parseUserAgentOsName(ua);
136
- out.osVersion = parseUserAgentOsVersion(ua);
137
- out.platformString = ua;
138
- out.productName = '';
139
- out.supportedAbis = [];
140
- // totalMemory: navigator.deviceMemory is in GiB; convert to bytes. -1 when absent.
141
- out.totalMemory = devMem >= 0 ? devMem * 1024 * 1024 * 1024 : -1;
142
- // webViewVersion is not exposed by browsers (we are the browser).
143
- out.webViewVersion = '';
144
- return out;
145
- },
146
- getSafeAreaInsets(out) {
147
- // Reading CSS env(safe-area-inset-*) requires a probe element in the DOM. The web backend
148
- // returns zero insets by default. Call enableWebSafeAreaInsets() to mount a live CSS-var probe
149
- // that updates this when the device reports real insets (notched PWAs).
150
- const insets = _safeAreaInsets;
151
- if (insets !== null) {
152
- out.bottom = insets.bottom;
153
- out.left = insets.left;
154
- out.right = insets.right;
155
- out.top = insets.top;
156
- }
157
- else {
158
- out.bottom = 0;
159
- out.left = 0;
160
- out.right = 0;
161
- out.top = 0;
162
- }
163
- return out;
164
- },
165
- };
166
- }
167
- export function enableWebSafeAreaInsets() {
168
- if (typeof document === 'undefined')
169
- return () => { };
170
- const el = document.createElement('div');
171
- el.style.cssText =
172
- 'position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);' +
173
- 'bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);' +
174
- 'pointer-events:none;visibility:hidden;';
175
- document.body.appendChild(el);
176
- function readInsets() {
177
- const style = getComputedStyle(el);
178
- _safeAreaInsets = {
179
- bottom: parseFloat(style.bottom) || 0,
180
- left: parseFloat(style.left) || 0,
181
- right: parseFloat(style.right) || 0,
182
- top: parseFloat(style.top) || 0,
183
- };
184
- }
185
- readInsets();
186
- const observer = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(readInsets) : null;
187
- if (observer !== null)
188
- observer.observe(document.documentElement);
189
- return () => {
190
- if (observer !== null)
191
- observer.disconnect();
192
- el.parentNode?.removeChild(el);
193
- _safeAreaInsets = null;
194
- };
195
- }
196
- export function explainDeviceBackend() {
197
- if (_custom !== null) {
198
- return { conflict: _hostConflict, layer: 'custom', operation: null, viability: 'unobserved' };
199
- }
200
- if (_host !== null) {
201
- return {
202
- conflict: _hostConflict,
203
- layer: 'host',
204
- operation: _hostObservation !== null ? _hostObservation.operation : null,
205
- viability: _hostObservation !== null ? _hostObservation.viability : 'unobserved',
206
- };
207
- }
208
- return { conflict: false, layer: 'host-not-enabled', operation: null, viability: 'unobserved' };
209
- }
210
- export function getDeviceBackend() {
211
- return _custom ?? _host ?? _sentinel;
52
+ export function getDeviceCapabilities(host, out) {
53
+ return host.system.device.getCapabilities(out);
212
54
  }
213
- export function getDeviceCapabilities(out) {
214
- return getDeviceBackend().getCapabilities(out);
55
+ export function getDeviceDisplayMetrics(host, out) {
56
+ return host.system.device.getDisplayMetrics(out);
215
57
  }
216
- export function getDeviceDisplayMetrics(out) {
217
- return getDeviceBackend().getDisplayMetrics(out);
58
+ export function getDeviceId(host) {
59
+ return host.system.device.getId();
218
60
  }
219
- export function getDeviceId() {
220
- return getDeviceBackend().getId();
61
+ export function getDeviceInfo(host, out) {
62
+ return host.system.device.getInfo(out);
221
63
  }
222
- export function getDeviceInfo(out) {
223
- return getDeviceBackend().getInfo(out);
224
- }
225
- export function getSafeAreaInsets(out) {
226
- return getDeviceBackend().getSafeAreaInsets(out);
227
- }
228
- export function installDeviceHostBackend(backend) {
229
- if (_host !== null) {
230
- if (_host !== backend)
231
- _hostConflict = true;
232
- return;
233
- }
234
- _host = backend;
64
+ export function getSafeAreaInsets(host, out) {
65
+ return host.system.device.getSafeAreaInsets(out);
235
66
  }
236
- export function observeDeviceHostResult(operation, succeeded) {
237
- _hostObservation = {
238
- operation,
239
- viability: succeeded ? 'available' : 'runtime-api-unavailable',
240
- };
241
- }
242
- export function refreshDeviceInfo() {
243
- const backend = getDeviceBackend();
67
+ export function refreshDeviceInfo(host) {
68
+ const backend = host.system.device;
244
69
  const maybeRefreshable = backend;
245
70
  if (typeof maybeRefreshable.refresh === 'function') {
246
71
  maybeRefreshable.refresh();
247
72
  }
248
73
  }
249
- export function resetDeviceBackendForTest() {
250
- _custom = null;
251
- _host = null;
252
- _hostConflict = false;
253
- _hostObservation = null;
254
- }
255
- export function setDeviceBackend(backend) {
256
- _custom = backend;
257
- }
258
- const _sentinel = {
259
- getCapabilities(out) {
260
- out.hasKeyboard = false;
261
- out.hasMouse = false;
262
- out.hasStylus = false;
263
- return out;
264
- },
265
- getDisplayMetrics(out) {
266
- out.colorDepth = -1;
267
- out.densityDpi = -1;
268
- out.logicalHeight = -1;
269
- out.logicalWidth = -1;
270
- out.physicalHeight = -1;
271
- out.physicalWidth = -1;
272
- out.pixelRatio = -1;
273
- return out;
274
- },
275
- getId() {
276
- return '';
277
- },
278
- getInfo(out) {
279
- out.arch = '';
280
- out.availableMemory = -1;
281
- out.boardName = '';
282
- out.colorGamut = '';
283
- out.cpuCores = -1;
284
- out.fontScale = -1;
285
- out.formFactor = DeviceFormFactorUnknown;
286
- out.gpuRenderer = '';
287
- out.gpuVendor = '';
288
- out.isHdr = false;
289
- out.isJailbroken = false;
290
- out.isLowEndDevice = false;
291
- out.isRooted = false;
292
- out.isVirtual = false;
293
- out.manufacturer = '';
294
- out.marketingName = '';
295
- out.model = '';
296
- out.osBuild = '';
297
- out.osName = '';
298
- out.osVersion = '';
299
- out.platformString = '';
300
- out.productName = '';
301
- out.supportedAbis = [];
302
- out.totalMemory = -1;
303
- out.webViewVersion = '';
304
- return out;
305
- },
306
- getSafeAreaInsets(out) {
307
- out.bottom = 0;
308
- out.left = 0;
309
- out.right = 0;
310
- out.top = 0;
311
- return out;
312
- },
313
- };
314
- let _custom = null;
315
- let _host = null;
316
- let _hostConflict = false;
317
- let _hostObservation = null;
318
- let _safeAreaInsets = null;
319
- function detectColorGamut() {
320
- if (typeof matchMedia === 'undefined')
321
- return '';
322
- if (matchMedia('(color-gamut: rec2020)').matches)
323
- return 'rec2020';
324
- if (matchMedia('(color-gamut: p3)').matches)
325
- return 'p3';
326
- if (matchMedia('(color-gamut: srgb)').matches)
327
- return 'srgb';
328
- return '';
329
- }
330
- function detectDesktopUa(ua) {
331
- return /win(?:dows)?nt|macintosh|mac os x|linux(?!.*android)|cros|x11/i.test(ua);
332
- }
333
- function detectHdr() {
334
- if (typeof matchMedia === 'undefined')
335
- return false;
336
- return matchMedia('(dynamic-range: high)').matches;
337
- }
338
- function detectLowEndDevice(deviceMemoryGib, cores) {
339
- // Low-end heuristic: <= 1 GiB RAM or <= 2 cores. Both sentinels (-1) = unknown = false.
340
- if (deviceMemoryGib > 0 && deviceMemoryGib <= 1)
341
- return true;
342
- if (cores > 0 && cores <= 2)
343
- return true;
344
- return false;
345
- }
346
- function readWebGpuInfo() {
347
- // Reads WEBGL_debug_renderer_info from a transient WebGL context. Returns '' when unavailable or
348
- // blocked by browser privacy budget. This is best-effort — modern browsers may mask or randomize.
349
- try {
350
- if (typeof document === 'undefined')
351
- return { renderer: '', vendor: '' };
352
- const canvas = document.createElement('canvas');
353
- const gl = canvas.getContext('webgl') ??
354
- canvas.getContext('experimental-webgl');
355
- if (gl === null)
356
- return { renderer: '', vendor: '' };
357
- const ext = gl.getExtension('WEBGL_debug_renderer_info');
358
- if (ext === null)
359
- return { renderer: '', vendor: '' };
360
- const vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL) ?? '';
361
- const renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL) ?? '';
362
- return { renderer, vendor };
363
- }
364
- catch {
365
- return { renderer: '', vendor: '' };
366
- }
367
- }
368
74
  //# sourceMappingURL=device.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO;QACL,UAAU,EAAE,CAAC,CAAC;QACd,UAAU,EAAE,CAAC,CAAC;QACd,aAAa,EAAE,CAAC,CAAC;QACjB,YAAY,EAAE,CAAC,CAAC;QAChB,cAAc,EAAE,CAAC,CAAC;QAClB,aAAa,EAAE,CAAC,CAAC;QACjB,UAAU,EAAE,CAAC,CAAC;KACf,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,IAAI,EAAE,EAAE;QACR,eAAe,EAAE,CAAC,CAAC;QACnB,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,CAAC,CAAC;QACZ,SAAS,EAAE,CAAC,CAAC;QACb,UAAU,EAAE,uBAAuB;QACnC,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,KAAK;QACZ,YAAY,EAAE,KAAK;QACnB,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE;QAChB,aAAa,EAAE,EAAE;QACjB,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,EAAE;QACb,cAAc,EAAE,EAAE;QAClB,WAAW,EAAE,EAAE;QACf,aAAa,EAAE,EAAE;QACjB,WAAW,EAAE,CAAC,CAAC;QACf,cAAc,EAAE,EAAE;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAqB,EAAE,GAAuB;IAClF,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAqB,EAAE,GAAyB;IACtF,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAqB;IAC/C,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAqB,EAAE,GAAe;IAClE,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAqB,EAAE,GAAmB;IAC1E,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IACnC,MAAM,gBAAgB,GAAG,OAA8C,CAAC;IACxE,IAAI,OAAO,gBAAgB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACnD,gBAAgB,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { enableWebSafeAreaInsets, explainDeviceBackend, getDeviceCapabilities, getDeviceDisplayMetrics, getDeviceId, getDeviceInfo, getSafeAreaInsets, refreshDeviceInfo, } from './contract';
1
+ export { createDeviceCapabilities, createDeviceDisplayMetrics, createDeviceInfo, createSafeAreaInsets, getDeviceCapabilities, getDeviceDisplayMetrics, getDeviceId, getDeviceInfo, getSafeAreaInsets, refreshDeviceInfo, } from './contract';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { enableWebSafeAreaInsets, explainDeviceBackend, getDeviceCapabilities, getDeviceDisplayMetrics, getDeviceId, getDeviceInfo, getSafeAreaInsets, refreshDeviceInfo, } from './contract';
1
+ export { createDeviceCapabilities, createDeviceDisplayMetrics, createDeviceInfo, createSafeAreaInsets, getDeviceCapabilities, getDeviceDisplayMetrics, getDeviceId, getDeviceInfo, getSafeAreaInsets, refreshDeviceInfo, } from './contract';
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/device",
3
- "version": "0.5.0-next.1944.cd6b6e7",
3
+ "version": "0.5.1-edge.638.d4dbd4e",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,8 +38,8 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/types": "0.5.0-next.1944.cd6b6e7",
42
- "@flighthq/useragent": "0.5.0-next.1944.cd6b6e7"
41
+ "@flighthq/types": "0.5.1-edge.638.d4dbd4e",
42
+ "@flighthq/useragent": "0.5.1-edge.638.d4dbd4e"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.3.0"
@@ -3,29 +3,23 @@ import type {
3
3
  DeviceCapabilities,
4
4
  DeviceDisplayMetrics,
5
5
  DeviceInfo,
6
+ HasSystemDevice,
6
7
  SafeAreaInsets,
7
8
  } from '@flighthq/types/contract';
8
- import { DeviceFormFactorDesktop, DeviceFormFactorPhone, DeviceFormFactorUnknown } from '@flighthq/types/contract';
9
+ import { DeviceFormFactorUnknown } from '@flighthq/types/contract';
9
10
 
11
+ import * as deviceContract from './device';
10
12
  import {
11
13
  createDeviceCapabilities,
12
14
  createDeviceDisplayMetrics,
13
15
  createDeviceInfo,
14
16
  createSafeAreaInsets,
15
- createWebDeviceBackend,
16
- enableWebSafeAreaInsets,
17
- getDeviceBackend,
18
17
  getDeviceCapabilities,
19
18
  getDeviceDisplayMetrics,
20
19
  getDeviceId,
21
20
  getDeviceInfo,
22
21
  getSafeAreaInsets,
23
22
  refreshDeviceInfo,
24
- setDeviceBackend,
25
- explainDeviceBackend,
26
- installDeviceHostBackend,
27
- observeDeviceHostResult,
28
- resetDeviceBackendForTest,
29
23
  } from './device';
30
24
 
31
25
  function fakeBackend(): DeviceBackend {
@@ -87,7 +81,9 @@ function fakeBackend(): DeviceBackend {
87
81
  };
88
82
  }
89
83
 
90
- afterEach(() => setDeviceBackend(null));
84
+ function fakeHost(): HasSystemDevice {
85
+ return { system: { device: fakeBackend() } };
86
+ }
91
87
 
92
88
  describe('createDeviceCapabilities', () => {
93
89
  it('allocates a zeroed snapshot with all false capability flags', () => {
@@ -148,148 +144,11 @@ describe('createSafeAreaInsets', () => {
148
144
  });
149
145
  });
150
146
 
151
- describe('createWebDeviceBackend', () => {
152
- it('fills the snapshot with sentinels without throwing (jsdom)', () => {
153
- const backend = createWebDeviceBackend();
154
- const info = backend.getInfo(createDeviceInfo());
155
- expect(info.model).toBe('');
156
- expect(info.manufacturer).toBe('');
157
- expect(info.marketingName).toBe('');
158
- expect(info.productName).toBe('');
159
- expect(info.boardName).toBe('');
160
- expect(info.webViewVersion).toBe('');
161
- expect(info.colorGamut).toBe('');
162
- expect(info.fontScale).toBe(-1);
163
- expect(info.isHdr).toBe(false);
164
- expect(typeof info.totalMemory).toBe('number');
165
- expect(info.availableMemory).toBe(-1);
166
- expect(typeof info.cpuCores).toBe('number');
167
- expect(info.isJailbroken).toBe(false);
168
- expect(info.isRooted).toBe(false);
169
- expect(info.osBuild).toBe('');
170
- expect(typeof info.formFactor).toBe('string');
171
- expect(typeof info.arch).toBe('string');
172
- expect(info.platformString).toBe(navigator.userAgent);
173
- expect(Array.isArray(info.supportedAbis)).toBe(true);
174
- expect(info.supportedAbis.length).toBe(0);
175
- });
176
-
177
- it('returns zero safe-area insets on plain web (no CSS probe)', () => {
178
- const backend = createWebDeviceBackend();
179
- expect(backend.getSafeAreaInsets(createSafeAreaInsets())).toEqual({ bottom: 0, left: 0, right: 0, top: 0 });
180
- });
181
-
182
- it('getId returns a string (empty or a UUID) without throwing', () => {
183
- const backend = createWebDeviceBackend();
184
- const id = backend.getId();
185
- expect(typeof id).toBe('string');
186
- });
187
-
188
- it('getId returns the same value on repeated calls (stable install id)', () => {
189
- const backend = createWebDeviceBackend();
190
- const id1 = backend.getId();
191
- const id2 = backend.getId();
192
- if (id1 !== '') {
193
- expect(id1).toBe(id2);
194
- }
195
- });
196
-
197
- it('returns display metrics with a valid pixel ratio from jsdom', () => {
198
- const backend = createWebDeviceBackend();
199
- const metrics = backend.getDisplayMetrics(createDeviceDisplayMetrics());
200
- // jsdom exposes window.devicePixelRatio = 1 and screen.width/height
201
- expect(typeof metrics.pixelRatio).toBe('number');
202
- expect(typeof metrics.logicalWidth).toBe('number');
203
- });
204
-
205
- it('totalMemory converts deviceMemory GiB to bytes', () => {
206
- // Patch navigator.deviceMemory to a known value
207
- const nav = navigator as unknown as Record<string, unknown>;
208
- const original = nav['deviceMemory'];
209
- try {
210
- Object.defineProperty(navigator, 'deviceMemory', { configurable: true, value: 4 });
211
- const backend = createWebDeviceBackend();
212
- const info = backend.getInfo(createDeviceInfo());
213
- expect(info.totalMemory).toBe(4 * 1024 * 1024 * 1024);
214
- } finally {
215
- if (original !== undefined) {
216
- Object.defineProperty(navigator, 'deviceMemory', { configurable: true, value: original });
217
- } else {
218
- // jsdom has no deviceMemory; delete the injected one so it does not leak into a shared worker.
219
- delete (navigator as unknown as Record<string, unknown>)['deviceMemory'];
220
- }
221
- }
222
- });
223
-
224
- it('osVersion parses Android version from UA', () => {
225
- const backend = createWebDeviceBackend();
226
- const result = backend.getInfo(createDeviceInfo());
227
- // jsdom UA results in a string; actual parsing is covered by useragent unit tests
228
- expect(typeof result.osVersion).toBe('string');
229
- });
230
-
231
- it('getCapabilities returns a capability snapshot without throwing', () => {
232
- const backend = createWebDeviceBackend();
233
- const caps = backend.getCapabilities(createDeviceCapabilities());
234
- expect(typeof caps.hasKeyboard).toBe('boolean');
235
- expect(typeof caps.hasMouse).toBe('boolean');
236
- expect(caps.hasStylus).toBe(false);
237
- });
238
- });
239
-
240
- describe('enableWebSafeAreaInsets', () => {
241
- it('returns a dispose function and does not throw in jsdom', () => {
242
- const dispose = enableWebSafeAreaInsets();
243
- expect(typeof dispose).toBe('function');
244
- dispose();
245
- });
246
- });
247
-
248
- describe('explainDeviceBackend', () => {
249
- afterEach(() => resetDeviceBackendForTest());
250
-
251
- it('reports host-not-enabled when no backend is installed', () => {
252
- resetDeviceBackendForTest();
253
- const explanation = explainDeviceBackend();
254
- expect(explanation.layer).toBe('host-not-enabled');
255
- expect(explanation.conflict).toBe(false);
256
- expect(explanation.viability).toBe('unobserved');
257
- });
258
-
259
- it('reports custom layer when a custom backend is set', () => {
260
- setDeviceBackend(fakeBackend());
261
- expect(explainDeviceBackend().layer).toBe('custom');
262
- });
263
-
264
- it('reports host layer when a host backend is installed', () => {
265
- installDeviceHostBackend(fakeBackend());
266
- expect(explainDeviceBackend().layer).toBe('host');
267
- });
268
-
269
- it('reports conflict when two different host backends are installed', () => {
270
- installDeviceHostBackend(fakeBackend());
271
- installDeviceHostBackend(fakeBackend());
272
- expect(explainDeviceBackend().conflict).toBe(true);
273
- });
274
- });
275
-
276
- describe('getDeviceBackend', () => {
277
- it('falls back to a web backend when none is set', () => {
278
- expect(getDeviceBackend()).not.toBeNull();
279
- });
280
-
281
- it('returns the registered backend', () => {
282
- const backend = fakeBackend();
283
- setDeviceBackend(backend);
284
- expect(getDeviceBackend()).toBe(backend);
285
- });
286
- });
287
-
288
147
  describe('getDeviceCapabilities', () => {
289
- it('fills and returns out via the active backend', () => {
290
- setDeviceBackend(fakeBackend());
148
+ it('fills and returns out via the host backend', () => {
149
+ const host = fakeHost();
291
150
  const out = createDeviceCapabilities();
292
- const result = getDeviceCapabilities(out);
151
+ const result = getDeviceCapabilities(host, out);
293
152
  expect(result).toBe(out);
294
153
  expect(out.hasKeyboard).toBe(true);
295
154
  expect(out.hasMouse).toBe(true);
@@ -298,10 +157,10 @@ describe('getDeviceCapabilities', () => {
298
157
  });
299
158
 
300
159
  describe('getDeviceDisplayMetrics', () => {
301
- it('fills and returns out via the active backend', () => {
302
- setDeviceBackend(fakeBackend());
160
+ it('fills and returns out via the host backend', () => {
161
+ const host = fakeHost();
303
162
  const out = createDeviceDisplayMetrics();
304
- const result = getDeviceDisplayMetrics(out);
163
+ const result = getDeviceDisplayMetrics(host, out);
305
164
  expect(result).toBe(out);
306
165
  expect(out.colorDepth).toBe(8);
307
166
  expect(out.densityDpi).toBe(440);
@@ -314,29 +173,17 @@ describe('getDeviceDisplayMetrics', () => {
314
173
  });
315
174
 
316
175
  describe('getDeviceId', () => {
317
- it('returns a string without throwing', () => {
318
- expect(typeof getDeviceId()).toBe('string');
319
- });
320
-
321
- it('returns the value from a registered backend', () => {
322
- setDeviceBackend(fakeBackend());
323
- expect(getDeviceId()).toBe('test-device-id');
324
- });
325
-
326
- it('returns a stable value across two reads (web fallback)', () => {
327
- const id1 = getDeviceId();
328
- const id2 = getDeviceId();
329
- if (id1 !== '') {
330
- expect(id1).toBe(id2);
331
- }
176
+ it('returns the value from the host backend', () => {
177
+ const host = fakeHost();
178
+ expect(getDeviceId(host)).toBe('test-device-id');
332
179
  });
333
180
  });
334
181
 
335
182
  describe('getDeviceInfo', () => {
336
- it('fills and returns out via the active backend', () => {
337
- setDeviceBackend(fakeBackend());
183
+ it('fills and returns out via the host backend', () => {
184
+ const host = fakeHost();
338
185
  const out = createDeviceInfo();
339
- const result = getDeviceInfo(out);
186
+ const result = getDeviceInfo(host, out);
340
187
  expect(result).toBe(out);
341
188
  expect(out.arch).toBe('arm64');
342
189
  expect(out.availableMemory).toBe(3_000_000_000);
@@ -344,7 +191,7 @@ describe('getDeviceInfo', () => {
344
191
  expect(out.colorGamut).toBe('display-p3');
345
192
  expect(out.cpuCores).toBe(8);
346
193
  expect(out.fontScale).toBe(1.2);
347
- expect(out.formFactor).toBe(DeviceFormFactorPhone);
194
+ expect(out.formFactor).toBe('Phone');
348
195
  expect(out.gpuRenderer).toBe('Adreno 650');
349
196
  expect(out.gpuVendor).toBe('Qualcomm');
350
197
  expect(out.isHdr).toBe(true);
@@ -364,66 +211,42 @@ describe('getDeviceInfo', () => {
364
211
  expect(out.totalMemory).toBe(8_000_000_000);
365
212
  expect(out.webViewVersion).toBe('120.0.6099.230');
366
213
  });
367
-
368
- it('web backend returns Desktop formFactor for desktop UA', () => {
369
- const backend = createWebDeviceBackend();
370
- const info = backend.getInfo(createDeviceInfo());
371
- // jsdom uses a desktop UA, so formFactor should be Desktop or Unknown
372
- expect([DeviceFormFactorDesktop, DeviceFormFactorUnknown]).toContain(info.formFactor);
373
- });
374
214
  });
375
215
 
376
216
  describe('getSafeAreaInsets', () => {
377
- it('fills and returns out via the active backend', () => {
378
- setDeviceBackend(fakeBackend());
217
+ it('fills and returns out via the host backend', () => {
218
+ const host = fakeHost();
379
219
  const out = createSafeAreaInsets();
380
- const result = getSafeAreaInsets(out);
220
+ const result = getSafeAreaInsets(host, out);
381
221
  expect(result).toBe(out);
382
222
  expect(out.top).toBe(24);
383
223
  expect(out.bottom).toBe(16);
384
224
  });
385
225
  });
386
226
 
387
- describe('installDeviceHostBackend', () => {
388
- afterEach(() => resetDeviceBackendForTest());
389
-
390
- it('installs a host backend that getDeviceBackend returns', () => {
391
- const backend = fakeBackend();
392
- installDeviceHostBackend(backend);
393
- expect(getDeviceBackend()).toBe(backend);
394
- });
395
-
396
- it('is first-host-wins: a second different backend sets conflict', () => {
397
- const first = fakeBackend();
398
- const second = fakeBackend();
399
- installDeviceHostBackend(first);
400
- installDeviceHostBackend(second);
401
- expect(getDeviceBackend()).toBe(first);
402
- expect(explainDeviceBackend().conflict).toBe(true);
403
- });
404
- });
405
-
406
- describe('observeDeviceHostResult', () => {
407
- afterEach(() => resetDeviceBackendForTest());
408
-
409
- it('records a successful observation', () => {
410
- installDeviceHostBackend(fakeBackend());
411
- observeDeviceHostResult('getCapabilities', true);
412
- const explanation = explainDeviceBackend();
413
- expect(explanation.operation).toBe('getCapabilities');
414
- expect(explanation.viability).toBe('available');
415
- });
416
-
417
- it('records a failed observation', () => {
418
- installDeviceHostBackend(fakeBackend());
419
- observeDeviceHostResult('getCapabilities', false);
420
- expect(explainDeviceBackend().viability).toBe('runtime-api-unavailable');
227
+ describe('R3 boundary', () => {
228
+ it('exports no ambient-state API (setDeviceBackend, getDeviceBackend, etc.)', () => {
229
+ const exports = Object.keys(deviceContract);
230
+ const deletedSymbols = [
231
+ 'createWebDeviceBackend',
232
+ 'enableWebSafeAreaInsets',
233
+ 'explainDeviceBackend',
234
+ 'getDeviceBackend',
235
+ 'installDeviceHostBackend',
236
+ 'observeDeviceHostResult',
237
+ 'resetDeviceBackendForTest',
238
+ 'setDeviceBackend',
239
+ ];
240
+ for (const symbol of deletedSymbols) {
241
+ expect(exports).not.toContain(symbol);
242
+ }
421
243
  });
422
244
  });
423
245
 
424
246
  describe('refreshDeviceInfo', () => {
425
- it('does not throw on the default web backend', () => {
426
- expect(() => refreshDeviceInfo()).not.toThrow();
247
+ it('does not throw on a backend without refresh', () => {
248
+ const host = fakeHost();
249
+ expect(() => refreshDeviceInfo(host)).not.toThrow();
427
250
  });
428
251
 
429
252
  it('calls refresh() on backends that expose it', () => {
@@ -434,32 +257,8 @@ describe('refreshDeviceInfo', () => {
434
257
  refreshed = true;
435
258
  },
436
259
  };
437
- setDeviceBackend(backend);
438
- refreshDeviceInfo();
260
+ const host: HasSystemDevice = { system: { device: backend } };
261
+ refreshDeviceInfo(host);
439
262
  expect(refreshed).toBe(true);
440
263
  });
441
264
  });
442
-
443
- describe('resetDeviceBackendForTest', () => {
444
- it('clears all backend slots', () => {
445
- setDeviceBackend(fakeBackend());
446
- installDeviceHostBackend(fakeBackend());
447
- observeDeviceHostResult('getCapabilities', true);
448
- resetDeviceBackendForTest();
449
- expect(explainDeviceBackend().layer).toBe('host-not-enabled');
450
- expect(explainDeviceBackend().conflict).toBe(false);
451
- expect(explainDeviceBackend().viability).toBe('unobserved');
452
- });
453
- });
454
-
455
- describe('setDeviceBackend', () => {
456
- it('clears back to the web fallback when passed null', () => {
457
- setDeviceBackend(fakeBackend());
458
- setDeviceBackend(null);
459
- expect(getDeviceBackend()).not.toBeNull();
460
- // After reset, should be the web backend (not the fake)
461
- const out = createDeviceInfo();
462
- getDeviceInfo(out);
463
- expect(out.model).toBe('');
464
- });
465
- });