@moldable-ai/ui 0.2.17 → 0.2.19

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.
Files changed (232) hide show
  1. package/dist/components/chat/chat-panel.d.ts +18 -12
  2. package/dist/components/chat/chat-panel.d.ts.map +1 -1
  3. package/dist/components/chat/chat-panel.js +73 -19
  4. package/dist/components/chat/index.d.ts +2 -1
  5. package/dist/components/chat/index.d.ts.map +1 -1
  6. package/dist/components/chat/index.js +2 -1
  7. package/dist/components/chat/model-effort-power-effects.d.ts +7 -0
  8. package/dist/components/chat/model-effort-power-effects.d.ts.map +1 -0
  9. package/dist/components/chat/model-effort-power-effects.js +54 -0
  10. package/dist/components/chat/model-effort-selector.d.ts +26 -0
  11. package/dist/components/chat/model-effort-selector.d.ts.map +1 -0
  12. package/dist/components/chat/model-effort-selector.js +179 -0
  13. package/dist/components/chat/model-effort-ultra-effects.d.ts +5 -0
  14. package/dist/components/chat/model-effort-ultra-effects.d.ts.map +1 -0
  15. package/dist/components/chat/model-effort-ultra-effects.js +56 -0
  16. package/dist/components/chat/tool-handlers.d.ts.map +1 -1
  17. package/dist/components/hardware/bluetooth-panel-helpers.d.ts +9 -0
  18. package/dist/components/hardware/bluetooth-panel-helpers.d.ts.map +1 -0
  19. package/dist/components/hardware/bluetooth-panel-helpers.js +37 -0
  20. package/dist/components/hardware/bluetooth-panel.d.ts +56 -0
  21. package/dist/components/hardware/bluetooth-panel.d.ts.map +1 -0
  22. package/dist/components/hardware/bluetooth-panel.js +470 -0
  23. package/dist/components/hardware/camera-preview.d.ts +39 -0
  24. package/dist/components/hardware/camera-preview.d.ts.map +1 -0
  25. package/dist/components/hardware/camera-preview.js +228 -0
  26. package/dist/components/hardware/capability-badge.d.ts +23 -0
  27. package/dist/components/hardware/capability-badge.d.ts.map +1 -0
  28. package/dist/components/hardware/capability-badge.js +39 -0
  29. package/dist/components/hardware/capability-matrix.d.ts +14 -0
  30. package/dist/components/hardware/capability-matrix.d.ts.map +1 -0
  31. package/dist/components/hardware/capability-matrix.js +97 -0
  32. package/dist/components/hardware/clipboard-button.d.ts +26 -0
  33. package/dist/components/hardware/clipboard-button.d.ts.map +1 -0
  34. package/dist/components/hardware/clipboard-button.js +114 -0
  35. package/dist/components/hardware/device-io-controls.d.ts +4 -0
  36. package/dist/components/hardware/device-io-controls.d.ts.map +1 -0
  37. package/dist/components/hardware/device-io-controls.js +28 -0
  38. package/dist/components/hardware/device-list.d.ts +20 -0
  39. package/dist/components/hardware/device-list.d.ts.map +1 -0
  40. package/dist/components/hardware/device-list.js +14 -0
  41. package/dist/components/hardware/display-map.d.ts +23 -0
  42. package/dist/components/hardware/display-map.d.ts.map +1 -0
  43. package/dist/components/hardware/display-map.js +114 -0
  44. package/dist/components/hardware/haptic-button.d.ts +26 -0
  45. package/dist/components/hardware/haptic-button.d.ts.map +1 -0
  46. package/dist/components/hardware/haptic-button.js +94 -0
  47. package/dist/components/hardware/hardware-panel.d.ts +11 -0
  48. package/dist/components/hardware/hardware-panel.d.ts.map +1 -0
  49. package/dist/components/hardware/hardware-panel.js +28 -0
  50. package/dist/components/hardware/hid-panel.d.ts +40 -0
  51. package/dist/components/hardware/hid-panel.d.ts.map +1 -0
  52. package/dist/components/hardware/hid-panel.js +373 -0
  53. package/dist/components/hardware/index.d.ts +27 -0
  54. package/dist/components/hardware/index.d.ts.map +1 -0
  55. package/dist/components/hardware/index.js +26 -0
  56. package/dist/components/hardware/live-indicator.d.ts +15 -0
  57. package/dist/components/hardware/live-indicator.d.ts.map +1 -0
  58. package/dist/components/hardware/live-indicator.js +26 -0
  59. package/dist/components/hardware/local-auth-button.d.ts +33 -0
  60. package/dist/components/hardware/local-auth-button.d.ts.map +1 -0
  61. package/dist/components/hardware/local-auth-button.js +115 -0
  62. package/dist/components/hardware/location-panel.d.ts +29 -0
  63. package/dist/components/hardware/location-panel.d.ts.map +1 -0
  64. package/dist/components/hardware/location-panel.js +154 -0
  65. package/dist/components/hardware/microphone-meter.d.ts +35 -0
  66. package/dist/components/hardware/microphone-meter.d.ts.map +1 -0
  67. package/dist/components/hardware/microphone-meter.js +244 -0
  68. package/dist/components/hardware/midi-monitor.d.ts +54 -0
  69. package/dist/components/hardware/midi-monitor.d.ts.map +1 -0
  70. package/dist/components/hardware/midi-monitor.js +534 -0
  71. package/dist/components/hardware/notification-panel.d.ts +24 -0
  72. package/dist/components/hardware/notification-panel.d.ts.map +1 -0
  73. package/dist/components/hardware/notification-panel.js +124 -0
  74. package/dist/components/hardware/power-blocker-controller.d.ts +19 -0
  75. package/dist/components/hardware/power-blocker-controller.d.ts.map +1 -0
  76. package/dist/components/hardware/power-blocker-controller.js +83 -0
  77. package/dist/components/hardware/power-panel.d.ts +67 -0
  78. package/dist/components/hardware/power-panel.d.ts.map +1 -0
  79. package/dist/components/hardware/power-panel.js +309 -0
  80. package/dist/components/hardware/readout.d.ts +10 -0
  81. package/dist/components/hardware/readout.d.ts.map +1 -0
  82. package/dist/components/hardware/readout.js +11 -0
  83. package/dist/components/hardware/screen-share-preview.d.ts +36 -0
  84. package/dist/components/hardware/screen-share-preview.d.ts.map +1 -0
  85. package/dist/components/hardware/screen-share-preview.js +191 -0
  86. package/dist/components/hardware/secure-storage-panel.d.ts +36 -0
  87. package/dist/components/hardware/secure-storage-panel.d.ts.map +1 -0
  88. package/dist/components/hardware/secure-storage-panel.js +193 -0
  89. package/dist/components/hardware/serial-console.d.ts +64 -0
  90. package/dist/components/hardware/serial-console.d.ts.map +1 -0
  91. package/dist/components/hardware/serial-console.js +399 -0
  92. package/dist/components/hardware/shortcut-recorder.d.ts +35 -0
  93. package/dist/components/hardware/shortcut-recorder.d.ts.map +1 -0
  94. package/dist/components/hardware/shortcut-recorder.js +217 -0
  95. package/dist/components/hardware/stream-log.d.ts +35 -0
  96. package/dist/components/hardware/stream-log.d.ts.map +1 -0
  97. package/dist/components/hardware/stream-log.js +65 -0
  98. package/dist/components/hardware/system-audio-monitor.d.ts +34 -0
  99. package/dist/components/hardware/system-audio-monitor.d.ts.map +1 -0
  100. package/dist/components/hardware/system-audio-monitor.js +275 -0
  101. package/dist/components/hardware/usb-panel.d.ts +54 -0
  102. package/dist/components/hardware/usb-panel.d.ts.map +1 -0
  103. package/dist/components/hardware/usb-panel.js +363 -0
  104. package/dist/components/hardware/use-capability.d.ts +20 -0
  105. package/dist/components/hardware/use-capability.d.ts.map +1 -0
  106. package/dist/components/hardware/use-capability.js +61 -0
  107. package/dist/components/ui/input-group.d.ts +1 -1
  108. package/dist/components/ui/slider.d.ts +4 -1
  109. package/dist/components/ui/slider.d.ts.map +1 -1
  110. package/dist/components/ui/slider.js +2 -2
  111. package/dist/index.d.ts +3 -1
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +5 -1
  114. package/dist/lib/commands.d.ts +59 -0
  115. package/dist/lib/commands.d.ts.map +1 -1
  116. package/dist/lib/commands.js +97 -0
  117. package/dist/lib/native-hardware/bluetooth-access.d.ts +14 -0
  118. package/dist/lib/native-hardware/bluetooth-access.d.ts.map +1 -0
  119. package/dist/lib/native-hardware/bluetooth-access.js +40 -0
  120. package/dist/lib/native-hardware/bluetooth-connection.d.ts +19 -0
  121. package/dist/lib/native-hardware/bluetooth-connection.d.ts.map +1 -0
  122. package/dist/lib/native-hardware/bluetooth-connection.js +88 -0
  123. package/dist/lib/native-hardware/bluetooth-gatt.d.ts +7 -0
  124. package/dist/lib/native-hardware/bluetooth-gatt.d.ts.map +1 -0
  125. package/dist/lib/native-hardware/bluetooth-gatt.js +77 -0
  126. package/dist/lib/native-hardware/bluetooth-internal.d.ts +10 -0
  127. package/dist/lib/native-hardware/bluetooth-internal.d.ts.map +1 -0
  128. package/dist/lib/native-hardware/bluetooth-internal.js +105 -0
  129. package/dist/lib/native-hardware/bluetooth-native-fallback.d.ts +33 -0
  130. package/dist/lib/native-hardware/bluetooth-native-fallback.d.ts.map +1 -0
  131. package/dist/lib/native-hardware/bluetooth-native-fallback.js +214 -0
  132. package/dist/lib/native-hardware/bluetooth-types.d.ts +85 -0
  133. package/dist/lib/native-hardware/bluetooth-types.d.ts.map +1 -0
  134. package/dist/lib/native-hardware/bluetooth-types.js +2 -0
  135. package/dist/lib/native-hardware/bluetooth.d.ts +7 -0
  136. package/dist/lib/native-hardware/bluetooth.d.ts.map +1 -0
  137. package/dist/lib/native-hardware/bluetooth.js +4 -0
  138. package/dist/lib/native-hardware/bridge.d.ts +23 -0
  139. package/dist/lib/native-hardware/bridge.d.ts.map +1 -0
  140. package/dist/lib/native-hardware/bridge.js +266 -0
  141. package/dist/lib/native-hardware/capabilities.d.ts +7 -0
  142. package/dist/lib/native-hardware/capabilities.d.ts.map +1 -0
  143. package/dist/lib/native-hardware/capabilities.js +95 -0
  144. package/dist/lib/native-hardware/clipboard.d.ts +11 -0
  145. package/dist/lib/native-hardware/clipboard.d.ts.map +1 -0
  146. package/dist/lib/native-hardware/clipboard.js +55 -0
  147. package/dist/lib/native-hardware/device-io-errors.d.ts +11 -0
  148. package/dist/lib/native-hardware/device-io-errors.d.ts.map +1 -0
  149. package/dist/lib/native-hardware/device-io-errors.js +82 -0
  150. package/dist/lib/native-hardware/displays.d.ts +38 -0
  151. package/dist/lib/native-hardware/displays.d.ts.map +1 -0
  152. package/dist/lib/native-hardware/displays.js +12 -0
  153. package/dist/lib/native-hardware/global-shortcuts.d.ts +86 -0
  154. package/dist/lib/native-hardware/global-shortcuts.d.ts.map +1 -0
  155. package/dist/lib/native-hardware/global-shortcuts.js +351 -0
  156. package/dist/lib/native-hardware/haptics.d.ts +25 -0
  157. package/dist/lib/native-hardware/haptics.d.ts.map +1 -0
  158. package/dist/lib/native-hardware/haptics.js +18 -0
  159. package/dist/lib/native-hardware/hid-native.d.ts +26 -0
  160. package/dist/lib/native-hardware/hid-native.d.ts.map +1 -0
  161. package/dist/lib/native-hardware/hid-native.js +229 -0
  162. package/dist/lib/native-hardware/hid.d.ts +52 -0
  163. package/dist/lib/native-hardware/hid.d.ts.map +1 -0
  164. package/dist/lib/native-hardware/hid.js +160 -0
  165. package/dist/lib/native-hardware/index.d.ts +38 -0
  166. package/dist/lib/native-hardware/index.d.ts.map +1 -0
  167. package/dist/lib/native-hardware/index.js +20 -0
  168. package/dist/lib/native-hardware/local-authentication.d.ts +32 -0
  169. package/dist/lib/native-hardware/local-authentication.d.ts.map +1 -0
  170. package/dist/lib/native-hardware/local-authentication.js +46 -0
  171. package/dist/lib/native-hardware/location.d.ts +49 -0
  172. package/dist/lib/native-hardware/location.d.ts.map +1 -0
  173. package/dist/lib/native-hardware/location.js +114 -0
  174. package/dist/lib/native-hardware/media-permissions.d.ts +28 -0
  175. package/dist/lib/native-hardware/media-permissions.d.ts.map +1 -0
  176. package/dist/lib/native-hardware/media-permissions.js +37 -0
  177. package/dist/lib/native-hardware/media.d.ts +17 -0
  178. package/dist/lib/native-hardware/media.d.ts.map +1 -0
  179. package/dist/lib/native-hardware/media.js +99 -0
  180. package/dist/lib/native-hardware/midi-access.d.ts +13 -0
  181. package/dist/lib/native-hardware/midi-access.d.ts.map +1 -0
  182. package/dist/lib/native-hardware/midi-access.js +66 -0
  183. package/dist/lib/native-hardware/midi-internal.d.ts +12 -0
  184. package/dist/lib/native-hardware/midi-internal.d.ts.map +1 -0
  185. package/dist/lib/native-hardware/midi-internal.js +88 -0
  186. package/dist/lib/native-hardware/midi-native-fallback.d.ts +27 -0
  187. package/dist/lib/native-hardware/midi-native-fallback.d.ts.map +1 -0
  188. package/dist/lib/native-hardware/midi-native-fallback.js +127 -0
  189. package/dist/lib/native-hardware/midi-ports.d.ts +6 -0
  190. package/dist/lib/native-hardware/midi-ports.d.ts.map +1 -0
  191. package/dist/lib/native-hardware/midi-ports.js +115 -0
  192. package/dist/lib/native-hardware/midi-types.d.ts +25 -0
  193. package/dist/lib/native-hardware/midi-types.d.ts.map +1 -0
  194. package/dist/lib/native-hardware/midi-types.js +1 -0
  195. package/dist/lib/native-hardware/midi.d.ts +6 -0
  196. package/dist/lib/native-hardware/midi.d.ts.map +1 -0
  197. package/dist/lib/native-hardware/midi.js +3 -0
  198. package/dist/lib/native-hardware/native-device-io.d.ts +28 -0
  199. package/dist/lib/native-hardware/native-device-io.d.ts.map +1 -0
  200. package/dist/lib/native-hardware/native-device-io.js +91 -0
  201. package/dist/lib/native-hardware/native-device-lifecycle.d.ts +13 -0
  202. package/dist/lib/native-hardware/native-device-lifecycle.d.ts.map +1 -0
  203. package/dist/lib/native-hardware/native-device-lifecycle.js +40 -0
  204. package/dist/lib/native-hardware/notifications.d.ts +38 -0
  205. package/dist/lib/native-hardware/notifications.d.ts.map +1 -0
  206. package/dist/lib/native-hardware/notifications.js +50 -0
  207. package/dist/lib/native-hardware/power-session.d.ts +113 -0
  208. package/dist/lib/native-hardware/power-session.d.ts.map +1 -0
  209. package/dist/lib/native-hardware/power-session.js +264 -0
  210. package/dist/lib/native-hardware/secure-storage.d.ts +36 -0
  211. package/dist/lib/native-hardware/secure-storage.d.ts.map +1 -0
  212. package/dist/lib/native-hardware/secure-storage.js +64 -0
  213. package/dist/lib/native-hardware/serial-native.d.ts +23 -0
  214. package/dist/lib/native-hardware/serial-native.d.ts.map +1 -0
  215. package/dist/lib/native-hardware/serial-native.js +181 -0
  216. package/dist/lib/native-hardware/serial.d.ts +76 -0
  217. package/dist/lib/native-hardware/serial.d.ts.map +1 -0
  218. package/dist/lib/native-hardware/serial.js +212 -0
  219. package/dist/lib/native-hardware/system-audio.d.ts +127 -0
  220. package/dist/lib/native-hardware/system-audio.d.ts.map +1 -0
  221. package/dist/lib/native-hardware/system-audio.js +330 -0
  222. package/dist/lib/native-hardware/types.d.ts +62 -0
  223. package/dist/lib/native-hardware/types.d.ts.map +1 -0
  224. package/dist/lib/native-hardware/types.js +27 -0
  225. package/dist/lib/native-hardware/usb-native.d.ts +39 -0
  226. package/dist/lib/native-hardware/usb-native.d.ts.map +1 -0
  227. package/dist/lib/native-hardware/usb-native.js +217 -0
  228. package/dist/lib/native-hardware/usb.d.ts +85 -0
  229. package/dist/lib/native-hardware/usb.d.ts.map +1 -0
  230. package/dist/lib/native-hardware/usb.js +222 -0
  231. package/package.json +1 -1
  232. package/src/styles/index.css +377 -0
@@ -0,0 +1,351 @@
1
+ import { NativeHardwareBridgeError, callNativeHardwareBridge, } from './bridge';
2
+ export const NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE = 'moldable:native-global-shortcuts';
3
+ export const NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE = 'moldable:native-global-shortcuts-result';
4
+ export const NATIVE_GLOBAL_SHORTCUT_EVENT_TYPE = 'moldable:native-global-shortcut-event';
5
+ export const NATIVE_GLOBAL_SHORTCUT_MAX_LENGTH = 128;
6
+ export const NATIVE_GLOBAL_SHORTCUT_MAX_PER_APP = 32;
7
+ const MODIFIERS = new Set([
8
+ 'alt',
9
+ 'altgr',
10
+ 'capslock',
11
+ 'cmd',
12
+ 'cmdorctrl',
13
+ 'command',
14
+ 'commandorcontrol',
15
+ 'control',
16
+ 'ctrl',
17
+ 'fn',
18
+ 'fnlock',
19
+ 'hyper',
20
+ 'meta',
21
+ 'numlock',
22
+ 'option',
23
+ 'scrolllock',
24
+ 'shift',
25
+ 'super',
26
+ 'symbol',
27
+ 'symbollock',
28
+ ]);
29
+ const handlers = new Map();
30
+ const pendingEvents = new Map();
31
+ const MAX_PENDING_REGISTRATIONS = 64;
32
+ let listeningWindow = null;
33
+ function isRecord(value) {
34
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
35
+ }
36
+ export function isMoldableGlobalShortcut(value) {
37
+ if (typeof value !== 'string' || value !== value.trim())
38
+ return false;
39
+ if (value.length < 3 || value.length > NATIVE_GLOBAL_SHORTCUT_MAX_LENGTH) {
40
+ return false;
41
+ }
42
+ if (/\s/u.test(value) ||
43
+ [...value].some((character) => {
44
+ const code = character.charCodeAt(0);
45
+ return code <= 31 || code === 127;
46
+ })) {
47
+ return false;
48
+ }
49
+ const parts = value.split('+');
50
+ if (parts.length < 2 || parts.length > 8)
51
+ return false;
52
+ if (parts.some((part) => !/^[A-Za-z0-9]{1,32}$/u.test(part)))
53
+ return false;
54
+ const normalized = parts.map((part) => part.toLowerCase());
55
+ if (new Set(normalized).size !== normalized.length)
56
+ return false;
57
+ if (!normalized.slice(0, -1).every((part) => MODIFIERS.has(part))) {
58
+ return false;
59
+ }
60
+ return !MODIFIERS.has(normalized[normalized.length - 1] ?? '');
61
+ }
62
+ function isGlobalShortcutEvent(value) {
63
+ return (isRecord(value) &&
64
+ value.type === NATIVE_GLOBAL_SHORTCUT_EVENT_TYPE &&
65
+ typeof value.registrationId === 'string' &&
66
+ value.registrationId.length > 0 &&
67
+ isMoldableGlobalShortcut(value.shortcut) &&
68
+ (value.state === 'Pressed' || value.state === 'Released'));
69
+ }
70
+ function handleShortcutMessage(event) {
71
+ if (event.source !== window.parent || !isGlobalShortcutEvent(event.data)) {
72
+ return;
73
+ }
74
+ const handler = handlers.get(event.data.registrationId);
75
+ if (handler) {
76
+ try {
77
+ handler({
78
+ registrationId: event.data.registrationId,
79
+ shortcut: event.data.shortcut,
80
+ state: event.data.state,
81
+ });
82
+ }
83
+ catch {
84
+ // One app callback must not break delivery for other registrations.
85
+ }
86
+ return;
87
+ }
88
+ if (!pendingEvents.has(event.data.registrationId) &&
89
+ pendingEvents.size >= MAX_PENDING_REGISTRATIONS) {
90
+ return;
91
+ }
92
+ const queued = pendingEvents.get(event.data.registrationId) ?? [];
93
+ if (queued.length < 4)
94
+ queued.push(event.data);
95
+ pendingEvents.set(event.data.registrationId, queued);
96
+ }
97
+ function ensureGlobalShortcutListener() {
98
+ if (typeof window === 'undefined' || listeningWindow === window)
99
+ return;
100
+ if (listeningWindow) {
101
+ listeningWindow.removeEventListener('message', handleShortcutMessage);
102
+ }
103
+ window.addEventListener('message', handleShortcutMessage);
104
+ listeningWindow = window;
105
+ }
106
+ function bindHandler(registrationId, handler) {
107
+ handlers.set(registrationId, handler);
108
+ const queued = pendingEvents.get(registrationId) ?? [];
109
+ pendingEvents.delete(registrationId);
110
+ for (const event of queued) {
111
+ try {
112
+ handler({
113
+ registrationId: event.registrationId,
114
+ shortcut: event.shortcut,
115
+ state: event.state,
116
+ });
117
+ }
118
+ catch {
119
+ // Callback errors do not change a successfully created registration.
120
+ }
121
+ }
122
+ }
123
+ function invalidShortcutError() {
124
+ return new NativeHardwareBridgeError({
125
+ code: 'invalid_request',
126
+ message: 'A global shortcut must contain modifiers and one key, for example CommandOrControl+Shift+P.',
127
+ retryable: false,
128
+ });
129
+ }
130
+ function canonicalShortcut(shortcut) {
131
+ const aliases = {
132
+ cmd: 'meta',
133
+ command: 'meta',
134
+ cmdorctrl: 'commandorcontrol',
135
+ ctrl: 'control',
136
+ option: 'alt',
137
+ };
138
+ return shortcut
139
+ .split('+')
140
+ .map((part) => aliases[part.toLowerCase()] ?? part.toLowerCase())
141
+ .join('+');
142
+ }
143
+ function makeRegistrationId() {
144
+ if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
145
+ return `native-shortcut-${crypto.randomUUID()}`;
146
+ }
147
+ return `native-shortcut-${Date.now()}-${Math.random().toString(36).slice(2)}`;
148
+ }
149
+ function makeRegistration(result) {
150
+ let active = true;
151
+ return {
152
+ registrationId: result.registrationId,
153
+ shortcut: result.shortcut,
154
+ async unregister(unregisterOptions = {}) {
155
+ if (!active)
156
+ return;
157
+ await unregisterMoldableGlobalShortcut(result.registrationId, unregisterOptions);
158
+ active = false;
159
+ },
160
+ };
161
+ }
162
+ export async function registerMoldableGlobalShortcut(shortcut, handler, options = {}) {
163
+ if (!isMoldableGlobalShortcut(shortcut) || typeof handler !== 'function') {
164
+ throw invalidShortcutError();
165
+ }
166
+ ensureGlobalShortcutListener();
167
+ const registrationId = makeRegistrationId();
168
+ let result;
169
+ try {
170
+ result =
171
+ await callNativeHardwareBridge({
172
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
173
+ capability: 'global-shortcuts',
174
+ action: 'register',
175
+ registrationId,
176
+ shortcut,
177
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
178
+ if (result.registered !== true ||
179
+ result.registrationId !== registrationId ||
180
+ result.shortcut !== shortcut) {
181
+ throw new NativeHardwareBridgeError({
182
+ code: 'invalid_response',
183
+ message: 'Moldable returned an invalid global shortcut registration.',
184
+ details: result,
185
+ retryable: false,
186
+ });
187
+ }
188
+ }
189
+ catch (error) {
190
+ if (error instanceof NativeHardwareBridgeError &&
191
+ (error.code === 'timeout' ||
192
+ error.code === 'aborted' ||
193
+ error.code === 'invalid_response')) {
194
+ void unregisterMoldableGlobalShortcut(registrationId).catch(() => {
195
+ // App-view teardown remains the final cleanup boundary.
196
+ });
197
+ }
198
+ throw error;
199
+ }
200
+ bindHandler(result.registrationId, handler);
201
+ return makeRegistration(result);
202
+ }
203
+ export async function registerAllMoldableGlobalShortcuts(shortcuts, handler, options = {}) {
204
+ if (!Array.isArray(shortcuts) ||
205
+ shortcuts.length === 0 ||
206
+ shortcuts.length > NATIVE_GLOBAL_SHORTCUT_MAX_PER_APP ||
207
+ typeof handler !== 'function' ||
208
+ !shortcuts.every(isMoldableGlobalShortcut) ||
209
+ new Set(shortcuts.map(canonicalShortcut)).size !== shortcuts.length) {
210
+ throw invalidShortcutError();
211
+ }
212
+ ensureGlobalShortcutListener();
213
+ const registrations = shortcuts.map((shortcut) => ({
214
+ registrationId: makeRegistrationId(),
215
+ shortcut,
216
+ }));
217
+ let result;
218
+ try {
219
+ result =
220
+ await callNativeHardwareBridge({
221
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
222
+ capability: 'global-shortcuts',
223
+ action: 'registerAll',
224
+ registrations,
225
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
226
+ if (result.registered !== true ||
227
+ !Array.isArray(result.registrations) ||
228
+ result.registrations.length !== registrations.length ||
229
+ result.registrations.some((registered, index) => {
230
+ const requested = registrations[index];
231
+ return (registered.registered !== true ||
232
+ registered.registrationId !== requested?.registrationId ||
233
+ registered.shortcut !== requested.shortcut);
234
+ })) {
235
+ throw new NativeHardwareBridgeError({
236
+ code: 'invalid_response',
237
+ message: 'Moldable returned invalid global shortcut registrations.',
238
+ details: result,
239
+ retryable: false,
240
+ });
241
+ }
242
+ }
243
+ catch (error) {
244
+ if (error instanceof NativeHardwareBridgeError &&
245
+ (error.code === 'timeout' ||
246
+ error.code === 'aborted' ||
247
+ error.code === 'host_error' ||
248
+ error.code === 'invalid_response')) {
249
+ void Promise.allSettled(registrations.map((registration) => unregisterMoldableGlobalShortcut(registration.registrationId)));
250
+ }
251
+ throw error;
252
+ }
253
+ for (const registration of result.registrations) {
254
+ bindHandler(registration.registrationId, handler);
255
+ }
256
+ return result.registrations.map(makeRegistration);
257
+ }
258
+ export async function isMoldableGlobalShortcutRegistered(shortcut, options = {}) {
259
+ if (!isMoldableGlobalShortcut(shortcut))
260
+ throw invalidShortcutError();
261
+ const result = await callNativeHardwareBridge({
262
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
263
+ capability: 'global-shortcuts',
264
+ action: 'isRegistered',
265
+ shortcut,
266
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
267
+ if (typeof result.registered !== 'boolean' || result.shortcut !== shortcut) {
268
+ throw new NativeHardwareBridgeError({
269
+ code: 'invalid_response',
270
+ message: 'Moldable returned an invalid global shortcut status.',
271
+ details: result,
272
+ retryable: false,
273
+ });
274
+ }
275
+ return result.registered;
276
+ }
277
+ export async function setMoldableGlobalShortcutsSuspended(suspended, options = {}) {
278
+ if (typeof suspended !== 'boolean') {
279
+ throw new NativeHardwareBridgeError({
280
+ code: 'invalid_request',
281
+ message: 'Global shortcut suspension must be a boolean.',
282
+ retryable: false,
283
+ });
284
+ }
285
+ const result = await callNativeHardwareBridge({
286
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
287
+ capability: 'global-shortcuts',
288
+ action: 'setSuspended',
289
+ suspended,
290
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
291
+ if (result.suspended !== suspended) {
292
+ throw new NativeHardwareBridgeError({
293
+ code: 'invalid_response',
294
+ message: 'Moldable returned an invalid global shortcut suspension state.',
295
+ details: result,
296
+ retryable: false,
297
+ });
298
+ }
299
+ }
300
+ export async function areMoldableGlobalShortcutsSuspended(options = {}) {
301
+ const result = await callNativeHardwareBridge({
302
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
303
+ capability: 'global-shortcuts',
304
+ action: 'isSuspended',
305
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
306
+ if (typeof result.suspended !== 'boolean') {
307
+ throw new NativeHardwareBridgeError({
308
+ code: 'invalid_response',
309
+ message: 'Moldable returned an invalid global shortcut suspension state.',
310
+ details: result,
311
+ retryable: false,
312
+ });
313
+ }
314
+ return result.suspended;
315
+ }
316
+ export async function unregisterMoldableGlobalShortcut(registrationId, options = {}) {
317
+ if (registrationId.trim().length === 0 || registrationId.length > 128) {
318
+ throw new NativeHardwareBridgeError({
319
+ code: 'invalid_request',
320
+ message: 'A valid global shortcut registration ID is required.',
321
+ retryable: false,
322
+ });
323
+ }
324
+ await callNativeHardwareBridge({
325
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
326
+ capability: 'global-shortcuts',
327
+ action: 'unregister',
328
+ registrationId,
329
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
330
+ handlers.delete(registrationId);
331
+ pendingEvents.delete(registrationId);
332
+ }
333
+ export async function unregisterAllMoldableGlobalShortcuts(options = {}) {
334
+ const result = await callNativeHardwareBridge({
335
+ type: NATIVE_GLOBAL_SHORTCUT_REQUEST_TYPE,
336
+ capability: 'global-shortcuts',
337
+ action: 'unregisterAll',
338
+ }, NATIVE_GLOBAL_SHORTCUT_RESULT_TYPE, options);
339
+ handlers.clear();
340
+ pendingEvents.clear();
341
+ return result;
342
+ }
343
+ /** Test-only reset for module-level event delivery state. */
344
+ export function resetMoldableGlobalShortcutClientForTests() {
345
+ if (listeningWindow) {
346
+ listeningWindow.removeEventListener('message', handleShortcutMessage);
347
+ }
348
+ listeningWindow = null;
349
+ handlers.clear();
350
+ pendingEvents.clear();
351
+ }
@@ -0,0 +1,25 @@
1
+ import { type NativeHardwareBridgeOptions } from './bridge';
2
+ export declare const NATIVE_HAPTICS_REQUEST_TYPE: "moldable:native-haptics";
3
+ export declare const NATIVE_HAPTICS_RESULT_TYPE: "moldable:native-haptics-result";
4
+ export type MoldableHapticPattern = 'generic' | 'alignment' | 'level-change';
5
+ export interface MoldableHapticAvailability {
6
+ /** Compatibility alias for apiAvailable. */
7
+ available: boolean;
8
+ /** Whether the host can submit feedback requests to the operating system. */
9
+ apiAvailable: boolean;
10
+ /** Physical haptic hardware cannot be detected reliably by the macOS API. */
11
+ hardwareStatus: 'unknown' | 'unavailable';
12
+ patterns: MoldableHapticPattern[];
13
+ reason?: string;
14
+ }
15
+ export interface MoldableHapticResult {
16
+ /** Compatibility alias indicating that the OS accepted the request. */
17
+ performed: true;
18
+ accepted: true;
19
+ /** macOS does not report whether compatible hardware produced feedback. */
20
+ physicalFeedback: 'unknown';
21
+ pattern: MoldableHapticPattern;
22
+ }
23
+ export declare function getMoldableHapticAvailability(options?: NativeHardwareBridgeOptions): Promise<MoldableHapticAvailability>;
24
+ export declare function performMoldableHapticFeedback(pattern?: MoldableHapticPattern, options?: NativeHardwareBridgeOptions): Promise<MoldableHapticResult>;
25
+ //# sourceMappingURL=haptics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"haptics.d.ts","sourceRoot":"","sources":["../../../src/lib/native-hardware/haptics.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,2BAA2B,EAEjC,MAAM,UAAU,CAAA;AAEjB,eAAO,MAAM,2BAA2B,EAAG,yBAAkC,CAAA;AAC7E,eAAO,MAAM,0BAA0B,EACrC,gCAAyC,CAAA;AAE3C,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,CAAA;AAE5E,MAAM,WAAW,0BAA0B;IACzC,4CAA4C;IAC5C,SAAS,EAAE,OAAO,CAAA;IAClB,6EAA6E;IAC7E,YAAY,EAAE,OAAO,CAAA;IACrB,6EAA6E;IAC7E,cAAc,EAAE,SAAS,GAAG,aAAa,CAAA;IACzC,QAAQ,EAAE,qBAAqB,EAAE,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,SAAS,EAAE,IAAI,CAAA;IACf,QAAQ,EAAE,IAAI,CAAA;IACd,2EAA2E;IAC3E,gBAAgB,EAAE,SAAS,CAAA;IAC3B,OAAO,EAAE,qBAAqB,CAAA;CAC/B;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,0BAA0B,CAAC,CAUrC;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,qBAAiC,EAC1C,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,oBAAoB,CAAC,CAW/B"}
@@ -0,0 +1,18 @@
1
+ import { callNativeHardwareBridge, } from './bridge';
2
+ export const NATIVE_HAPTICS_REQUEST_TYPE = 'moldable:native-haptics';
3
+ export const NATIVE_HAPTICS_RESULT_TYPE = 'moldable:native-haptics-result';
4
+ export function getMoldableHapticAvailability(options = {}) {
5
+ return callNativeHardwareBridge({
6
+ type: NATIVE_HAPTICS_REQUEST_TYPE,
7
+ capability: 'haptics',
8
+ action: 'getAvailability',
9
+ }, NATIVE_HAPTICS_RESULT_TYPE, options);
10
+ }
11
+ export function performMoldableHapticFeedback(pattern = 'generic', options = {}) {
12
+ return callNativeHardwareBridge({
13
+ type: NATIVE_HAPTICS_REQUEST_TYPE,
14
+ capability: 'haptics',
15
+ action: 'perform',
16
+ pattern,
17
+ }, NATIVE_HAPTICS_RESULT_TYPE, options);
18
+ }
@@ -0,0 +1,26 @@
1
+ import type { MoldableHidDevice, MoldableHidInputReportEvent } from './hid';
2
+ import { type MoldableNativeDeviceDescriptor } from './native-device-io';
3
+ export declare class NativeMoldableHidDevice extends EventTarget implements MoldableHidDevice {
4
+ readonly descriptor: MoldableNativeDeviceDescriptor;
5
+ readonly vendorId: number;
6
+ readonly productId: number;
7
+ readonly productName: string;
8
+ private handle?;
9
+ private closing?;
10
+ private inputPump?;
11
+ private readonly lifecycle;
12
+ constructor(descriptor: MoldableNativeDeviceDescriptor);
13
+ get opened(): boolean;
14
+ open(): Promise<void>;
15
+ close(): Promise<void>;
16
+ forget(): Promise<void>;
17
+ sendReport(reportId: number, data: BufferSource): Promise<void>;
18
+ sendFeatureReport(reportId: number, data: BufferSource): Promise<void>;
19
+ receiveFeatureReport(reportId: number): Promise<DataView>;
20
+ listen(listener: (event: MoldableHidInputReportEvent) => void, signal?: AbortSignal): () => void;
21
+ private startInputPump;
22
+ private readLoop;
23
+ private execute;
24
+ }
25
+ export declare function isNativeMoldableHidDevice(device: MoldableHidDevice): device is NativeMoldableHidDevice;
26
+ //# sourceMappingURL=hid-native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hid-native.d.ts","sourceRoot":"","sources":["../../../src/lib/native-hardware/hid-native.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,OAAO,CAAA;AAC3E,OAAO,EACL,KAAK,8BAA8B,EAMpC,MAAM,oBAAoB,CAAA;AAM3B,qBAAa,uBACX,SAAQ,WACR,YAAW,iBAAiB;IAUhB,QAAQ,CAAC,UAAU,EAAE,8BAA8B;IAR/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,OAAO,CAAC,MAAM,CAAC,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAC,CAAe;IAC/B,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;gBAEnC,UAAU,EAAE,8BAA8B;IAO/D,IAAI,MAAM,IAAI,OAAO,CAEpB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAerB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB/D,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAStE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAW/D,MAAM,CACJ,QAAQ,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,EACtD,MAAM,CAAC,EAAE,WAAW,GACnB,MAAM,IAAI;IAiBb,OAAO,CAAC,cAAc;YASR,QAAQ;YA6DR,OAAO;CA+BtB;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,GACxB,MAAM,IAAI,uBAAuB,CAEnC"}
@@ -0,0 +1,229 @@
1
+ import { NativeHardwareBridgeError } from './bridge';
2
+ import { bytesFromNativeDeviceResult, bytesWrittenFromNativeDeviceResult, closeMoldableNativeDevice, executeMoldableNativeDeviceOperation, openMoldableNativeDevice, } from './native-device-io';
3
+ import { NativeDeviceLifecycle, isNativeDeviceDisconnect, } from './native-device-lifecycle';
4
+ export class NativeMoldableHidDevice extends EventTarget {
5
+ descriptor;
6
+ vendorId;
7
+ productId;
8
+ productName;
9
+ handle;
10
+ closing;
11
+ inputPump;
12
+ lifecycle = new NativeDeviceLifecycle();
13
+ constructor(descriptor) {
14
+ super();
15
+ this.descriptor = descriptor;
16
+ this.vendorId = descriptor.vendorId ?? 0;
17
+ this.productId = descriptor.productId ?? 0;
18
+ this.productName = descriptor.label;
19
+ }
20
+ get opened() {
21
+ return this.lifecycle.opened;
22
+ }
23
+ async open() {
24
+ if (this.closing)
25
+ await this.closing;
26
+ if (this.handle && this.lifecycle.disconnected)
27
+ await this.close();
28
+ if (this.opened)
29
+ return;
30
+ const result = await openMoldableNativeDevice('hid', this.descriptor.selector, {});
31
+ if (result.kind !== 'hid')
32
+ throw new Error('Native device kind mismatch.');
33
+ this.handle = result.handle;
34
+ this.lifecycle.didOpen();
35
+ this.startInputPump();
36
+ }
37
+ async close() {
38
+ if (this.closing)
39
+ return this.closing;
40
+ if (!this.handle)
41
+ return;
42
+ const handle = this.handle;
43
+ this.inputPump?.abort();
44
+ this.inputPump = undefined;
45
+ const closing = closeMoldableNativeDevice('hid', handle)
46
+ .then(() => {
47
+ if (this.handle === handle) {
48
+ this.handle = undefined;
49
+ this.lifecycle.didClose();
50
+ }
51
+ })
52
+ .catch((error) => {
53
+ if (this.handle === handle && !this.lifecycle.disconnected) {
54
+ this.startInputPump();
55
+ }
56
+ throw error;
57
+ })
58
+ .finally(() => {
59
+ if (this.closing === closing)
60
+ this.closing = undefined;
61
+ });
62
+ this.closing = closing;
63
+ return closing;
64
+ }
65
+ async forget() {
66
+ await this.close();
67
+ }
68
+ async sendReport(reportId, data) {
69
+ assertReportId(reportId);
70
+ const payload = asBytes(data);
71
+ const bytes = new Uint8Array(payload.byteLength + 1);
72
+ bytes[0] = reportId;
73
+ bytes.set(payload, 1);
74
+ const result = await this.execute({
75
+ action: 'write',
76
+ endpoint: null,
77
+ data: [...bytes],
78
+ timeoutMs: 10_000,
79
+ bulk: false,
80
+ });
81
+ if (bytesWrittenFromNativeDeviceResult(result) !== bytes.byteLength) {
82
+ throw new NativeHardwareBridgeError({
83
+ code: 'host_error',
84
+ message: 'The HID device accepted only part of the output report.',
85
+ retryable: true,
86
+ });
87
+ }
88
+ }
89
+ async sendFeatureReport(reportId, data) {
90
+ assertReportId(reportId);
91
+ await this.execute({
92
+ action: 'hidSendFeature',
93
+ reportId,
94
+ data: [...asBytes(data)],
95
+ });
96
+ }
97
+ async receiveFeatureReport(reportId) {
98
+ assertReportId(reportId);
99
+ const result = await this.execute({
100
+ action: 'hidReceiveFeature',
101
+ reportId,
102
+ length: 4096,
103
+ });
104
+ const bytes = bytesFromNativeDeviceResult(result);
105
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
106
+ }
107
+ listen(listener, signal) {
108
+ if (signal?.aborted)
109
+ return () => undefined;
110
+ let active = true;
111
+ const handleReport = (event) => {
112
+ listener(event);
113
+ };
114
+ const stop = () => {
115
+ if (!active)
116
+ return;
117
+ active = false;
118
+ this.removeEventListener('inputreport', handleReport);
119
+ signal?.removeEventListener('abort', stop);
120
+ };
121
+ this.addEventListener('inputreport', handleReport);
122
+ signal?.addEventListener('abort', stop, { once: true });
123
+ return stop;
124
+ }
125
+ startInputPump() {
126
+ if (!this.handle || this.inputPump || this.lifecycle.disconnected)
127
+ return;
128
+ const controller = new AbortController();
129
+ this.inputPump = controller;
130
+ void this.readLoop(controller.signal).finally(() => {
131
+ if (this.inputPump === controller)
132
+ this.inputPump = undefined;
133
+ });
134
+ }
135
+ async readLoop(signal) {
136
+ while (!signal.aborted && this.handle) {
137
+ try {
138
+ const result = await this.execute({
139
+ action: 'hidReadInput',
140
+ length: 4096,
141
+ timeoutMs: 500,
142
+ }, signal);
143
+ if (result.kind !== 'hidInput' ||
144
+ !Number.isInteger(result.reportId) ||
145
+ Number(result.reportId) < 0 ||
146
+ Number(result.reportId) > 255) {
147
+ throw new NativeHardwareBridgeError({
148
+ code: 'invalid_response',
149
+ message: 'Moldable returned an invalid HID input report.',
150
+ details: result,
151
+ });
152
+ }
153
+ const bytes = bytesFromNativeDeviceResult({
154
+ kind: 'data',
155
+ data: result.data,
156
+ });
157
+ if (bytes.length === 0)
158
+ continue;
159
+ const event = new Event('inputreport');
160
+ Object.defineProperties(event, {
161
+ device: { value: this },
162
+ reportId: { value: Number(result.reportId) },
163
+ data: {
164
+ value: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength),
165
+ },
166
+ });
167
+ this.dispatchEvent(event);
168
+ }
169
+ catch (error) {
170
+ if (signal.aborted || !this.handle)
171
+ return;
172
+ if (error instanceof NativeHardwareBridgeError &&
173
+ error.code === 'timeout') {
174
+ continue;
175
+ }
176
+ if (isNativeDeviceDisconnect(error)) {
177
+ this.lifecycle.didDisconnect(this, error);
178
+ }
179
+ else {
180
+ const event = new Event('error');
181
+ Object.defineProperty(event, 'error', { value: error });
182
+ this.dispatchEvent(event);
183
+ }
184
+ return;
185
+ }
186
+ }
187
+ }
188
+ async execute(operation, signal) {
189
+ if (!this.handle) {
190
+ throw new NativeHardwareBridgeError({
191
+ code: 'invalid_request',
192
+ message: 'HID device is not open.',
193
+ });
194
+ }
195
+ if (this.lifecycle.disconnected) {
196
+ throw new NativeHardwareBridgeError({
197
+ code: 'unavailable',
198
+ message: 'HID device is disconnected.',
199
+ retryable: true,
200
+ });
201
+ }
202
+ try {
203
+ return await executeMoldableNativeDeviceOperation('hid', this.handle, operation, { signal });
204
+ }
205
+ catch (error) {
206
+ if (isNativeDeviceDisconnect(error)) {
207
+ this.lifecycle.didDisconnect(this, error);
208
+ }
209
+ throw error;
210
+ }
211
+ }
212
+ }
213
+ export function isNativeMoldableHidDevice(device) {
214
+ return device instanceof NativeMoldableHidDevice;
215
+ }
216
+ function asBytes(data) {
217
+ return data instanceof ArrayBuffer
218
+ ? new Uint8Array(data)
219
+ : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
220
+ }
221
+ function assertReportId(reportId) {
222
+ if (!Number.isInteger(reportId) || reportId < 0 || reportId > 0xff) {
223
+ throw new NativeHardwareBridgeError({
224
+ code: 'invalid_request',
225
+ message: 'HID reportId must be an integer between 0 and 255.',
226
+ retryable: false,
227
+ });
228
+ }
229
+ }