@stacksjs/desktop 0.2.21 → 0.2.24

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 (56) hide show
  1. package/dist/_bridge.d.ts +105 -0
  2. package/dist/app-info.d.ts +22 -0
  3. package/dist/apple-script.d.ts +8 -0
  4. package/dist/audio.d.ts +17 -0
  5. package/dist/battery.d.ts +15 -0
  6. package/dist/biometric.d.ts +14 -0
  7. package/dist/bluetooth.d.ts +52 -0
  8. package/dist/bonjour.d.ts +13 -0
  9. package/dist/capabilities.d.ts +31 -0
  10. package/dist/clipboard.d.ts +11 -0
  11. package/dist/continuity-camera.d.ts +10 -0
  12. package/dist/coreml.d.ts +6 -0
  13. package/dist/crash-reporter.d.ts +46 -0
  14. package/dist/deep-link.d.ts +10 -0
  15. package/dist/drag-out.d.ts +18 -0
  16. package/dist/file-associations.d.ts +5 -0
  17. package/dist/fs.d.ts +62 -0
  18. package/dist/global-shortcuts.d.ts +19 -0
  19. package/dist/handoff.d.ts +24 -0
  20. package/dist/hotkeys.d.ts +10 -8
  21. package/dist/iap.d.ts +79 -0
  22. package/dist/index.d.ts +322 -0
  23. package/dist/index.js +2505 -20
  24. package/dist/index.js.map +55 -7
  25. package/dist/keychain.d.ts +7 -0
  26. package/dist/live-activities.d.ts +11 -0
  27. package/dist/local-server.d.ts +23 -0
  28. package/dist/location.d.ts +29 -0
  29. package/dist/log.d.ts +7 -0
  30. package/dist/menu.d.ts +29 -0
  31. package/dist/midi.d.ts +17 -0
  32. package/dist/native-autolaunch.d.ts +6 -0
  33. package/dist/network.d.ts +33 -0
  34. package/dist/notifications.d.ts +56 -0
  35. package/dist/pdf.d.ts +5 -0
  36. package/dist/permissions.d.ts +21 -0
  37. package/dist/printing.d.ts +9 -0
  38. package/dist/screen-capture.d.ts +11 -0
  39. package/dist/screen.d.ts +18 -0
  40. package/dist/serial.d.ts +15 -0
  41. package/dist/service-menu.d.ts +10 -0
  42. package/dist/shell.d.ts +28 -0
  43. package/dist/speech-recognition.d.ts +12 -0
  44. package/dist/speech.d.ts +21 -0
  45. package/dist/spotlight.d.ts +12 -0
  46. package/dist/system.d.ts +16 -0
  47. package/dist/tags.d.ts +6 -0
  48. package/dist/test-utils.d.ts +17 -0
  49. package/dist/test-utils.js +108 -0
  50. package/dist/test-utils.js.map +10 -0
  51. package/dist/theme.d.ts +10 -0
  52. package/dist/touchbar.d.ts +29 -0
  53. package/dist/updater.d.ts +37 -0
  54. package/dist/vision.d.ts +17 -0
  55. package/dist/window-events.d.ts +20 -0
  56. package/package.json +5 -1
@@ -0,0 +1,7 @@
1
+ export declare const keychain: KeychainAPI;
2
+ export declare interface KeychainAPI {
3
+ set: (service: string, account: string, password: string) => Promise<void>
4
+ get: (service: string, account: string) => Promise<string | null>
5
+ delete: (service: string, account: string) => Promise<void>
6
+ has: (service: string, account: string) => Promise<boolean>
7
+ }
@@ -0,0 +1,11 @@
1
+ export declare const liveActivities: LiveActivitiesAPI;
2
+ export declare interface LiveActivityState {
3
+ title?: string
4
+ webpageURL?: string
5
+ state?: Record<string, unknown>
6
+ }
7
+ export declare interface LiveActivitiesAPI {
8
+ start: (type: string, state?: LiveActivityState) => Promise<boolean>
9
+ update: (state: LiveActivityState) => Promise<boolean>
10
+ stop: () => Promise<void>
11
+ }
@@ -0,0 +1,23 @@
1
+ export declare const localServer: LocalServerAPI;
2
+ export declare interface LocalServerStartResult {
3
+ port: number
4
+ started: boolean
5
+ alreadyRunning?: boolean
6
+ reason?: string
7
+ }
8
+ export declare interface LocalServerRequestEvent {
9
+ method: string
10
+ url: string
11
+ }
12
+ export declare interface LocalServerRespondOptions {
13
+ status?: number
14
+ body?: string
15
+ contentType?: string
16
+ }
17
+ export declare interface LocalServerAPI {
18
+ start: (port?: number, host?: string) => Promise<LocalServerStartResult>
19
+ stop: () => Promise<void>
20
+ respond: (options?: LocalServerRespondOptions) => Promise<void>
21
+ onRequest: (cb: (event: LocalServerRequestEvent) => void) => () => void
22
+ awaitOAuthCallback: (options?: { port?: number, host?: string, timeoutMs?: number, successHTML?: string }) => Promise<{ url: string, port: number }>
23
+ }
@@ -0,0 +1,29 @@
1
+ export declare const location: LocationAPI;
2
+ export declare interface LocationCoordinate {
3
+ latitude: number
4
+ longitude: number
5
+ altitude?: number
6
+ horizontalAccuracy?: number
7
+ verticalAccuracy?: number
8
+ speed?: number
9
+ }
10
+ export declare interface LocationWatchOptions {
11
+ mode?: 'continuous' | 'significant'
12
+ distanceFilter?: number
13
+ }
14
+ export declare interface LocationAPI {
15
+ requestPermission: (mode?: 'whenInUse' | 'always') => Promise<LocationAuthStatus>
16
+ getAuthorization: () => Promise<LocationAuthStatus>
17
+ getCurrentLocation: () => Promise<{ requested: boolean }>
18
+ startWatching: (options?: LocationWatchOptions) => Promise<boolean>
19
+ stopWatching: () => Promise<void>
20
+ onUpdate: (cb: (loc: LocationCoordinate) => void) => () => void
21
+ onError: (cb: (err: { message: string }) => void) => () => void
22
+ onAuthChanged: (cb: (info: { status: LocationAuthStatus }) => void) => () => void
23
+ }
24
+ export type LocationAuthStatus = | 'undetermined'
25
+ | 'restricted-or-denied'
26
+ | 'authorizedAlways'
27
+ | 'authorizedWhenInUse'
28
+ | 'not-supported'
29
+ | 'unknown';
package/dist/log.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export declare const log: LogAPI;
2
+ export declare interface LogAPI {
3
+ debug: (message: string) => Promise<void>
4
+ info: (message: string) => Promise<void>
5
+ warn: (message: string) => Promise<void>
6
+ error: (message: string) => Promise<void>
7
+ }
package/dist/menu.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ export declare const menu: MenuAPI;
2
+ export declare interface MenuItem {
3
+ id: string
4
+ label?: string
5
+ role?: string
6
+ accelerator?: string
7
+ separator?: boolean
8
+ checkable?: boolean
9
+ checked?: boolean
10
+ disabled?: boolean
11
+ submenu?: MenuItem[]
12
+ icon?: string
13
+ }
14
+ export declare interface MenuActionEvent {
15
+ id: string
16
+ }
17
+ export declare interface MenuAPI {
18
+ set: (items: MenuItem[]) => Promise<void>
19
+ setDock: (items: MenuItem[]) => Promise<void>
20
+ addItem: (parent: string, item: MenuItem) => Promise<void>
21
+ removeItem: (id: string) => Promise<void>
22
+ enableItem: (id: string) => Promise<void>
23
+ disableItem: (id: string) => Promise<void>
24
+ checkItem: (id: string) => Promise<void>
25
+ uncheckItem: (id: string) => Promise<void>
26
+ setItemLabel: (id: string, label: string) => Promise<void>
27
+ clearDock: () => Promise<void>
28
+ onAction: (cb: (event: MenuActionEvent) => void) => () => void
29
+ }
package/dist/midi.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ export declare const midi: MIDIAPI;
2
+ export declare interface MIDIEndpoint {
3
+ index: number
4
+ name: string
5
+ }
6
+ export declare interface MIDIMessageEvent {
7
+ index: number
8
+ data: number[]
9
+ }
10
+ export declare interface MIDIAPI {
11
+ listSources: () => Promise<MIDIEndpoint[]>
12
+ listDestinations: () => Promise<MIDIEndpoint[]>
13
+ send: (destinationIndex: number, data: Uint8Array | number[]) => Promise<{ ok: boolean, reason?: string }>
14
+ subscribe: (sourceIndex: number) => Promise<{ ok: boolean, reason?: string }>
15
+ unsubscribe: (sourceIndex: number) => Promise<{ ok: boolean }>
16
+ onMessage: (cb: (event: MIDIMessageEvent) => void) => () => void
17
+ }
@@ -0,0 +1,6 @@
1
+ export declare const nativeAutoLaunch: NativeAutoLaunchAPI;
2
+ export declare interface NativeAutoLaunchAPI {
3
+ enable: () => Promise<boolean>
4
+ disable: () => Promise<boolean>
5
+ isEnabled: () => Promise<boolean>
6
+ }
@@ -0,0 +1,33 @@
1
+ export declare const network: NetworkAPI;
2
+ export declare interface NetworkInterface {
3
+ name: string
4
+ address: string
5
+ isUp: boolean
6
+ isLoopback: boolean
7
+ }
8
+ export declare interface ProxySettings {
9
+ http?: string
10
+ https?: string
11
+ ftp?: string
12
+ socks?: string
13
+ exceptions?: string[]
14
+ }
15
+ export declare interface NetworkAPI {
16
+ connectionType: () => Promise<ConnectionType>
17
+ wifiSSID: () => Promise<string | undefined>
18
+ wifiSignalStrength: () => Promise<number | undefined>
19
+ ipAddress: () => Promise<string>
20
+ macAddress: () => Promise<string>
21
+ interfaces: () => Promise<NetworkInterface[]>
22
+ isVPNConnected: () => Promise<boolean>
23
+ proxySettings: () => Promise<ProxySettings>
24
+ openPreferences: () => Promise<void>
25
+ onChange: (cb: (info: { type: ConnectionType, online: boolean }) => void) => () => void
26
+ }
27
+ export type ConnectionType = | 'wifi'
28
+ | 'ethernet'
29
+ | 'cellular'
30
+ | 'bluetooth'
31
+ | 'vpn'
32
+ | 'none'
33
+ | 'unknown';
@@ -0,0 +1,56 @@
1
+ export declare const notifications: SystemNotifications;
2
+ export declare interface NotificationAttachment {
3
+ id?: string
4
+ url: string
5
+ type?: 'image' | 'audio' | 'video' | string
6
+ }
7
+ export declare interface NotificationAction {
8
+ id: string
9
+ title: string
10
+ style?: 'default' | 'destructive' | 'foreground'
11
+ authenticationRequired?: boolean
12
+ }
13
+ export declare interface NotificationOptions {
14
+ title: string
15
+ body?: string
16
+ subtitle?: string
17
+ id?: string
18
+ triggerAt?: string | number | Date
19
+ sound?: 'default' | 'silent' | string
20
+ icon?: string
21
+ badge?: number
22
+ data?: unknown
23
+ attachments?: NotificationAttachment[]
24
+ actions?: NotificationAction[]
25
+ reply?: {
26
+ placeholder?: string
27
+ sendButtonTitle?: string
28
+ }
29
+ categoryId?: string
30
+ threadId?: string
31
+ }
32
+ export declare interface NotificationActionEvent {
33
+ notificationId?: string
34
+ actionId: string
35
+ isDefault?: boolean
36
+ }
37
+ export declare interface NotificationReplyEvent {
38
+ notificationId?: string
39
+ text: string
40
+ }
41
+ export declare interface NotificationCategory {
42
+ id: string
43
+ actions: NotificationAction[]
44
+ }
45
+ export declare interface SystemNotifications {
46
+ show: (options: NotificationOptions) => Promise<void>
47
+ schedule: (options: NotificationOptions) => Promise<void>
48
+ cancel: (id: string) => Promise<void>
49
+ cancelAll: () => Promise<void>
50
+ setBadge: (n: number) => Promise<void>
51
+ clearBadge: () => Promise<void>
52
+ requestPermission: () => Promise<boolean>
53
+ registerCategories: (categories: NotificationCategory[]) => Promise<void>
54
+ onActionClicked: (cb: (event: NotificationActionEvent) => void) => () => void
55
+ onReply: (cb: (event: NotificationReplyEvent) => void) => () => void
56
+ }
package/dist/pdf.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare const pdf: PDFAPI;
2
+ export declare interface PDFAPI {
3
+ countPages: (path: string) => Promise<number>
4
+ extractText: (path: string) => Promise<string>
5
+ }
@@ -0,0 +1,21 @@
1
+ export declare const permissions: PermissionsAPI;
2
+ export declare interface PermissionsAPI {
3
+ check: (name: PermissionName) => Promise<PermissionStatus>
4
+ request: (name: PermissionName) => Promise<PermissionStatus>
5
+ openSettings: (name?: PermissionName) => Promise<void>
6
+ }
7
+ /** Status values match the macOS TCC convention. */
8
+ export type PermissionStatus = 'granted' | 'denied' | 'restricted' | 'undetermined' | 'not-supported';
9
+ export type PermissionName = | 'camera'
10
+ | 'microphone'
11
+ | 'screen_recording'
12
+ | 'accessibility'
13
+ | 'full_disk_access'
14
+ | 'input_monitoring'
15
+ | 'location'
16
+ | 'notifications'
17
+ | 'contacts'
18
+ | 'calendar'
19
+ | 'reminders'
20
+ | 'photos'
21
+ | 'bluetooth';
@@ -0,0 +1,9 @@
1
+ export declare const printing: PrintingAPI;
2
+ export declare interface PrintToPDFResult {
3
+ ok: boolean
4
+ path?: string
5
+ }
6
+ export declare interface PrintingAPI {
7
+ print: () => Promise<void>
8
+ printToPDF: (path: string) => Promise<PrintToPDFResult>
9
+ }
@@ -0,0 +1,11 @@
1
+ export declare const screenCapture: ScreenCaptureAPI;
2
+ export declare interface CapturableWindow {
3
+ id: number
4
+ name: string
5
+ ownerName: string
6
+ }
7
+ export declare interface ScreenCaptureAPI {
8
+ captureScreen: () => Promise<string | null>
9
+ captureWindow: (id: number) => Promise<string | null>
10
+ listWindows: () => Promise<CapturableWindow[]>
11
+ }
@@ -0,0 +1,18 @@
1
+ export declare const screen: ScreenAPI;
2
+ export declare interface Display {
3
+ id: number
4
+ x: number
5
+ y: number
6
+ width: number
7
+ height: number
8
+ workX: number
9
+ workY: number
10
+ workWidth: number
11
+ workHeight: number
12
+ scaleFactor: number
13
+ }
14
+ export declare interface ScreenAPI {
15
+ getDisplays: () => Promise<Display[]>
16
+ getPrimary: () => Promise<Display | null>
17
+ onChange: (cb: () => void) => () => void
18
+ }
@@ -0,0 +1,15 @@
1
+ export declare const serial: SerialAPI;
2
+ export declare interface SerialPort {
3
+ path: string
4
+ }
5
+ export declare interface SerialDataEvent {
6
+ id: string
7
+ data: number[]
8
+ }
9
+ export declare interface SerialAPI {
10
+ list: () => Promise<SerialPort[]>
11
+ open: (path: string, baud?: number) => Promise<{ id?: string, ok: boolean, reason?: string }>
12
+ write: (id: string, data: string) => Promise<{ ok: boolean, reason?: string }>
13
+ close: (id: string) => Promise<void>
14
+ onData: (cb: (event: SerialDataEvent) => void) => () => void
15
+ }
@@ -0,0 +1,10 @@
1
+ export declare const serviceMenu: ServiceMenuAPI;
2
+ export declare interface ServiceMenuInvokedEvent {
3
+ name: string
4
+ payload?: { type: string, value: string }
5
+ }
6
+ export declare interface ServiceMenuAPI {
7
+ register: (name: string) => Promise<{ ok: boolean, reason?: string }>
8
+ unregister: (name: string) => Promise<void>
9
+ onInvoked: (cb: (event: ServiceMenuInvokedEvent) => void) => () => void
10
+ }
@@ -0,0 +1,28 @@
1
+ export declare const shell: Shell;
2
+ export declare interface SpawnOptions {
3
+ cwd?: string
4
+ env?: Record<string, string>
5
+ streamOutput?: boolean
6
+ }
7
+ export declare interface Shell {
8
+ openExternal: (url: string) => Promise<void>
9
+ openPath: (path: string) => Promise<void>
10
+ showInFinder: (path: string) => Promise<void>
11
+ spawn: (id: string, command: string, args?: string[], opts?: SpawnOptions) => Promise<void>
12
+ kill: (id: string) => Promise<void>
13
+ getEnv: (name: string) => Promise<string | undefined>
14
+ setEnv: (name: string, value: string) => Promise<void>
15
+ onStdout: (cb: (event: ShellOutputEvent) => void) => () => void
16
+ onStderr: (cb: (event: ShellOutputEvent) => void) => () => void
17
+ onExit: (cb: (event: ShellExitEvent) => void) => () => void
18
+ }
19
+ /** Output chunk from a spawned process. */
20
+ export declare interface ShellOutputEvent {
21
+ id: string
22
+ data: string
23
+ }
24
+ export declare interface ShellExitEvent {
25
+ id: string
26
+ exitCode: number | null
27
+ signal?: string
28
+ }
@@ -0,0 +1,12 @@
1
+ export declare const speechRecognition: SpeechRecognitionAPI;
2
+ export declare interface SpeechRecognitionStartOptions {
3
+ language?: string
4
+ partialResults?: boolean
5
+ }
6
+ export declare interface SpeechRecognitionAPI {
7
+ isAvailable: () => Promise<boolean>
8
+ start: (opts?: SpeechRecognitionStartOptions) => Promise<{ started: boolean, reason?: string }>
9
+ stop: () => Promise<void>
10
+ onPartial: (cb: (e: { transcript: string }) => void) => () => void
11
+ onFinal: (cb: (e: { transcript: string }) => void) => () => void
12
+ }
@@ -0,0 +1,21 @@
1
+ export declare const speech: SpeechAPI;
2
+ export declare interface SpeakOptions {
3
+ voice?: string
4
+ rate?: number
5
+ pitch?: number
6
+ volume?: number
7
+ }
8
+ export declare interface SpeechVoice {
9
+ id: string
10
+ name: string
11
+ language: string
12
+ quality: 'default' | 'enhanced'
13
+ }
14
+ export declare interface SpeechAPI {
15
+ speak: (text: string, options?: SpeakOptions) => Promise<void>
16
+ stop: () => Promise<void>
17
+ pause: () => Promise<void>
18
+ resume: () => Promise<void>
19
+ isSpeaking: () => Promise<boolean>
20
+ getVoices: () => Promise<SpeechVoice[]>
21
+ }
@@ -0,0 +1,12 @@
1
+ export declare const spotlight: SpotlightAPI;
2
+ export declare interface SpotlightItem {
3
+ id: string
4
+ title: string
5
+ description?: string
6
+ keywords?: string[]
7
+ }
8
+ export declare interface SpotlightAPI {
9
+ index: (items: SpotlightItem[]) => Promise<{ ok: boolean, reason?: string }>
10
+ remove: (ids: string[]) => Promise<{ ok: boolean }>
11
+ removeAll: () => Promise<{ ok: boolean }>
12
+ }
@@ -0,0 +1,16 @@
1
+ export declare const system: SystemInfo;
2
+ export declare interface SystemInfo {
3
+ accentColor: () => Promise<string>
4
+ highlightColor: () => Promise<string>
5
+ language: () => Promise<string>
6
+ locale: () => Promise<string>
7
+ timezone: () => Promise<string>
8
+ is24HourTime: () => Promise<boolean>
9
+ reduceMotion: () => Promise<boolean>
10
+ reduceTransparency: () => Promise<boolean>
11
+ increaseContrast: () => Promise<boolean>
12
+ systemVersion: () => Promise<string>
13
+ hostname: () => Promise<string>
14
+ username: () => Promise<string>
15
+ openPreferences: () => Promise<void>
16
+ }
package/dist/tags.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export declare const tags: TagsAPI;
2
+ export declare interface TagsAPI {
3
+ get: (path: string) => Promise<string[]>
4
+ set: (path: string, tags: string[] | string) => Promise<boolean>
5
+ clear: (path: string) => Promise<boolean>
6
+ }
@@ -0,0 +1,17 @@
1
+ export declare function installMockBridge(initialNamespaces?: string[]): MockBridgeHandle;
2
+ /** Helper — find the first captured call matching `ns` + `method`. */
3
+ export declare function findCall(calls: CapturedCall[], ns: string, method: string): CapturedCall | undefined;
4
+ export declare interface CapturedCall {
5
+ ns: string
6
+ method: string
7
+ args: unknown[]
8
+ }
9
+ export declare interface MockBridgeHandle {
10
+ calls: CapturedCall[]
11
+ whenCalled: (
12
+ ns: string,
13
+ method: string,
14
+ response: unknown | ((...args: unknown[]) => unknown)
15
+ ) => void
16
+ uninstall: () => void
17
+ }
@@ -0,0 +1,108 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // src/test-utils.ts
5
+ ensureWindowEventTarget();
6
+ function ensureWindowEventTarget() {
7
+ if (typeof window === "undefined")
8
+ return;
9
+ const w = window;
10
+ if (typeof w.addEventListener === "function" && typeof w.dispatchEvent === "function")
11
+ return;
12
+ const listeners = new Map;
13
+ w.addEventListener = (name, cb) => {
14
+ let set = listeners.get(name);
15
+ if (!set) {
16
+ set = new Set;
17
+ listeners.set(name, set);
18
+ }
19
+ set.add(cb);
20
+ };
21
+ w.removeEventListener = (name, cb) => {
22
+ listeners.get(name)?.delete(cb);
23
+ };
24
+ w.dispatchEvent = (event) => {
25
+ const set = listeners.get(event.type);
26
+ if (set) {
27
+ for (const fn of set) {
28
+ try {
29
+ fn(event);
30
+ } catch {}
31
+ }
32
+ }
33
+ return true;
34
+ };
35
+ }
36
+ function installMockBridge(initialNamespaces = []) {
37
+ const calls = [];
38
+ const responses = new Map;
39
+ const previousRaw = window.craft;
40
+ const previous = previousRaw && previousRaw.__craft_bridge_loaded ? undefined : previousRaw;
41
+ function makeMethod(ns, method) {
42
+ return (...args) => {
43
+ calls.push({ ns, method, args });
44
+ const key = `${ns}:${method}`;
45
+ if (responses.has(key)) {
46
+ const r = responses.get(key);
47
+ const resolved = typeof r === "function" ? r(...args) : r;
48
+ return Promise.resolve(resolved);
49
+ }
50
+ return Promise.resolve(undefined);
51
+ };
52
+ }
53
+ function makeNamespace(ns) {
54
+ return new Proxy({}, {
55
+ get(_target, prop) {
56
+ if (typeof prop !== "string")
57
+ return;
58
+ if (responses.has(`${ns}:${prop}`)) {
59
+ const r = responses.get(`${ns}:${prop}`);
60
+ if (typeof r === "function" && r.length === 0) {
61
+ return () => {
62
+ calls.push({ ns, method: prop, args: [] });
63
+ return r();
64
+ };
65
+ }
66
+ }
67
+ return makeMethod(ns, prop);
68
+ }
69
+ });
70
+ }
71
+ const root = new Proxy({}, {
72
+ get(_target, prop) {
73
+ if (typeof prop !== "string")
74
+ return;
75
+ return makeNamespace(prop);
76
+ },
77
+ has(_target, prop) {
78
+ if (typeof prop !== "string")
79
+ return false;
80
+ if (initialNamespaces.length === 0)
81
+ return true;
82
+ return initialNamespaces.includes(prop);
83
+ }
84
+ });
85
+ window.craft = root;
86
+ return {
87
+ calls,
88
+ whenCalled(ns, method, response) {
89
+ responses.set(`${ns}:${method}`, response);
90
+ },
91
+ uninstall() {
92
+ if (previous === undefined) {
93
+ delete window.craft;
94
+ } else {
95
+ window.craft = previous;
96
+ }
97
+ }
98
+ };
99
+ }
100
+ function findCall(calls, ns, method) {
101
+ return calls.find((c) => c.ns === ns && c.method === method);
102
+ }
103
+ export {
104
+ installMockBridge,
105
+ findCall
106
+ };
107
+
108
+ //# debugId=112673127C3680E664756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/test-utils.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Test utilities — install a mock `window.craft` namespace + capture\n * every call against it. Apps consuming this package can `import {\n * installMockBridge } from '@stacksjs/desktop/test-utils'` to hand\n * their unit tests the same harness this package uses internally.\n *\n * The mock auto-vivifies namespaces on access — `craft.fs.readFile`\n * works without pre-declaring `fs`. Methods return a Promise resolving\n * to whatever was queued via `whenCalled`, defaulting to `undefined`.\n *\n * Tests should follow the install / call / assert / uninstall cycle:\n * ```ts\n * import { installMockBridge, findCall } from '@stacksjs/desktop/test-utils'\n * import { fs } from '@stacksjs/desktop'\n *\n * const bridge = installMockBridge()\n * bridge.whenCalled('fs', 'readFile', { data: 'hello' })\n * expect(await fs.readFile('/x')).toBe('hello')\n * expect(findCall(bridge.calls, 'fs', 'readFile')!.args).toEqual(['/x'])\n * bridge.uninstall()\n * ```\n *\n * Polyfills `window.addEventListener` / `dispatchEvent` for runners\n * (very-happy-dom, jsdom older versions) that don't ship them by\n * default — facade tests rely on those for event-based facades.\n */\n\nensureWindowEventTarget()\n\nfunction ensureWindowEventTarget(): void {\n if (typeof window === 'undefined') return\n const w = window as any\n if (typeof w.addEventListener === 'function' && typeof w.dispatchEvent === 'function') return\n\n const listeners = new Map<string, Set<EventListener>>()\n\n w.addEventListener = (name: string, cb: EventListener): void => {\n let set = listeners.get(name)\n if (!set) {\n set = new Set()\n listeners.set(name, set)\n }\n set.add(cb)\n }\n\n w.removeEventListener = (name: string, cb: EventListener): void => {\n listeners.get(name)?.delete(cb)\n }\n\n w.dispatchEvent = (event: Event): boolean => {\n const set = listeners.get(event.type)\n if (set) {\n for (const fn of set) {\n try { fn(event) } catch { /* swallow listener errors during tests */ }\n }\n }\n return true\n }\n}\n\nexport interface CapturedCall {\n ns: string\n method: string\n args: unknown[]\n}\n\nexport interface MockBridgeHandle {\n /** Calls captured since the bridge was installed. */\n calls: CapturedCall[]\n /**\n * Queue the response from `window.craft[ns][method]`. The mock\n * walks: explicit return → matched response handler → default.\n */\n whenCalled: (\n ns: string,\n method: string,\n response: unknown | ((...args: unknown[]) => unknown)\n ) => void\n /** Remove the mock and restore whatever was on window.craft before. */\n uninstall: () => void\n}\n\nexport function installMockBridge(initialNamespaces: string[] = []): MockBridgeHandle {\n const calls: CapturedCall[] = []\n const responses = new Map<string, unknown | ((...args: unknown[]) => unknown)>()\n\n // If the production bridge IIFE has already loaded — flagged via\n // `__craft_bridge_loaded` — treat the existing window.craft as\n // \"no real previous.\" Otherwise restoring it on uninstall would\n // leak the production facade into \"no bridge\" assertions in\n // subsequent tests.\n const previousRaw = (window as any).craft\n const previous = previousRaw && previousRaw.__craft_bridge_loaded ? undefined : previousRaw\n\n function makeMethod(ns: string, method: string) {\n return (...args: unknown[]) => {\n calls.push({ ns, method, args })\n const key = `${ns}:${method}`\n if (responses.has(key)) {\n const r = responses.get(key)\n const resolved = typeof r === 'function'\n ? (r as (...a: unknown[]) => unknown)(...args)\n : r\n return Promise.resolve(resolved)\n }\n return Promise.resolve(undefined)\n }\n }\n\n function makeNamespace(ns: string): Record<string, unknown> {\n return new Proxy({} as Record<string, unknown>, {\n get(_target, prop: string) {\n if (typeof prop !== 'string') return undefined\n // Some non-method properties may be read synchronously (e.g.\n // theme.get returns an object, not a promise). Allow callers\n // to register those by passing a zero-arg function — we\n // recognize the shape and return the value synchronously.\n if (responses.has(`${ns}:${prop}`)) {\n const r = responses.get(`${ns}:${prop}`)\n if (typeof r === 'function' && r.length === 0) {\n return () => {\n calls.push({ ns, method: prop, args: [] })\n return (r as () => unknown)()\n }\n }\n }\n return makeMethod(ns, prop)\n },\n })\n }\n\n const root = new Proxy({} as Record<string, unknown>, {\n get(_target, prop: string) {\n if (typeof prop !== 'string') return undefined\n return makeNamespace(prop)\n },\n has(_target, prop) {\n if (typeof prop !== 'string') return false\n if (initialNamespaces.length === 0) return true\n return initialNamespaces.includes(prop)\n },\n })\n\n ;(window as any).craft = root\n\n return {\n calls,\n whenCalled(ns, method, response) {\n responses.set(`${ns}:${method}`, response)\n },\n uninstall() {\n if (previous === undefined) {\n delete (window as any).craft\n }\n else {\n ;(window as any).craft = previous\n }\n },\n }\n}\n\n/** Helper — find the first captured call matching `ns` + `method`. */\nexport function findCall(\n calls: CapturedCall[],\n ns: string,\n method: string,\n): CapturedCall | undefined {\n return calls.find(c => c.ns === ns && c.method === method)\n}\n"
6
+ ],
7
+ "mappings": ";;;;AA2BA,wBAAwB;AAExB,SAAS,uBAAuB,GAAS;AAAA,EACvC,IAAI,OAAO,WAAW;AAAA,IAAa;AAAA,EACnC,MAAM,IAAI;AAAA,EACV,IAAI,OAAO,EAAE,qBAAqB,cAAc,OAAO,EAAE,kBAAkB;AAAA,IAAY;AAAA,EAEvF,MAAM,YAAY,IAAI;AAAA,EAEtB,EAAE,mBAAmB,CAAC,MAAc,OAA4B;AAAA,IAC9D,IAAI,MAAM,UAAU,IAAI,IAAI;AAAA,IAC5B,IAAI,CAAC,KAAK;AAAA,MACR,MAAM,IAAI;AAAA,MACV,UAAU,IAAI,MAAM,GAAG;AAAA,IACzB;AAAA,IACA,IAAI,IAAI,EAAE;AAAA;AAAA,EAGZ,EAAE,sBAAsB,CAAC,MAAc,OAA4B;AAAA,IACjE,UAAU,IAAI,IAAI,GAAG,OAAO,EAAE;AAAA;AAAA,EAGhC,EAAE,gBAAgB,CAAC,UAA0B;AAAA,IAC3C,MAAM,MAAM,UAAU,IAAI,MAAM,IAAI;AAAA,IACpC,IAAI,KAAK;AAAA,MACP,WAAW,MAAM,KAAK;AAAA,QACpB,IAAI;AAAA,UAAE,GAAG,KAAK;AAAA,UAAI,MAAM;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA;AA0BJ,SAAS,iBAAiB,CAAC,oBAA8B,CAAC,GAAqB;AAAA,EACpF,MAAM,QAAwB,CAAC;AAAA,EAC/B,MAAM,YAAY,IAAI;AAAA,EAOtB,MAAM,cAAe,OAAe;AAAA,EACpC,MAAM,WAAW,eAAe,YAAY,wBAAwB,YAAY;AAAA,EAEhF,SAAS,UAAU,CAAC,IAAY,QAAgB;AAAA,IAC9C,OAAO,IAAI,SAAoB;AAAA,MAC7B,MAAM,KAAK,EAAE,IAAI,QAAQ,KAAK,CAAC;AAAA,MAC/B,MAAM,MAAM,GAAG,MAAM;AAAA,MACrB,IAAI,UAAU,IAAI,GAAG,GAAG;AAAA,QACtB,MAAM,IAAI,UAAU,IAAI,GAAG;AAAA,QAC3B,MAAM,WAAW,OAAO,MAAM,aACzB,EAAmC,GAAG,IAAI,IAC3C;AAAA,QACJ,OAAO,QAAQ,QAAQ,QAAQ;AAAA,MACjC;AAAA,MACA,OAAO,QAAQ,QAAQ,SAAS;AAAA;AAAA;AAAA,EAIpC,SAAS,aAAa,CAAC,IAAqC;AAAA,IAC1D,OAAO,IAAI,MAAM,CAAC,GAA8B;AAAA,MAC9C,GAAG,CAAC,SAAS,MAAc;AAAA,QACzB,IAAI,OAAO,SAAS;AAAA,UAAU;AAAA,QAK9B,IAAI,UAAU,IAAI,GAAG,MAAM,MAAM,GAAG;AAAA,UAClC,MAAM,IAAI,UAAU,IAAI,GAAG,MAAM,MAAM;AAAA,UACvC,IAAI,OAAO,MAAM,cAAc,EAAE,WAAW,GAAG;AAAA,YAC7C,OAAO,MAAM;AAAA,cACX,MAAM,KAAK,EAAE,IAAI,QAAQ,MAAM,MAAM,CAAC,EAAE,CAAC;AAAA,cACzC,OAAQ,EAAoB;AAAA;AAAA,UAEhC;AAAA,QACF;AAAA,QACA,OAAO,WAAW,IAAI,IAAI;AAAA;AAAA,IAE9B,CAAC;AAAA;AAAA,EAGH,MAAM,OAAO,IAAI,MAAM,CAAC,GAA8B;AAAA,IACpD,GAAG,CAAC,SAAS,MAAc;AAAA,MACzB,IAAI,OAAO,SAAS;AAAA,QAAU;AAAA,MAC9B,OAAO,cAAc,IAAI;AAAA;AAAA,IAE3B,GAAG,CAAC,SAAS,MAAM;AAAA,MACjB,IAAI,OAAO,SAAS;AAAA,QAAU,OAAO;AAAA,MACrC,IAAI,kBAAkB,WAAW;AAAA,QAAG,OAAO;AAAA,MAC3C,OAAO,kBAAkB,SAAS,IAAI;AAAA;AAAA,EAE1C,CAAC;AAAA,EAEC,OAAe,QAAQ;AAAA,EAEzB,OAAO;AAAA,IACL;AAAA,IACA,UAAU,CAAC,IAAI,QAAQ,UAAU;AAAA,MAC/B,UAAU,IAAI,GAAG,MAAM,UAAU,QAAQ;AAAA;AAAA,IAE3C,SAAS,GAAG;AAAA,MACV,IAAI,aAAa,WAAW;AAAA,QAC1B,OAAQ,OAAe;AAAA,MACzB,EACK;AAAA,QACD,OAAe,QAAQ;AAAA;AAAA;AAAA,EAG/B;AAAA;AAIK,SAAS,QAAQ,CACtB,OACA,IACA,QAC0B;AAAA,EAC1B,OAAO,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM,EAAE,WAAW,MAAM;AAAA;",
8
+ "debugId": "112673127C3680E664756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,10 @@
1
+ export declare const theme: SystemTheme;
2
+ export declare interface ThemeInfo {
3
+ appearance: Appearance
4
+ }
5
+ export declare interface SystemTheme {
6
+ get: () => ThemeInfo
7
+ onChange: (cb: (info: ThemeInfo) => void) => () => void
8
+ current: () => Promise<ThemeInfo>
9
+ }
10
+ export type Appearance = 'light' | 'dark';
@@ -0,0 +1,29 @@
1
+ export declare const touchbar: TouchBarAPI;
2
+ export declare interface TouchBarItem {
3
+ id: string
4
+ type: TouchBarItemType
5
+ label?: string
6
+ icon?: string
7
+ value?: number
8
+ enabled?: boolean
9
+ segments?: Array<{ id: string, label?: string, icon?: string }>
10
+ }
11
+ export declare interface TouchBarActionEvent {
12
+ id: string
13
+ value?: number
14
+ segment?: string
15
+ }
16
+ export declare interface TouchBarAPI {
17
+ addItem: (item: TouchBarItem) => Promise<void>
18
+ removeItem: (id: string) => Promise<void>
19
+ updateItem: (id: string, props: Partial<TouchBarItem>) => Promise<void>
20
+ setLabel: (id: string, label: string) => Promise<void>
21
+ setIcon: (id: string, icon: string) => Promise<void>
22
+ setEnabled: (id: string, enabled: boolean) => Promise<void>
23
+ setSliderValue: (id: string, value: number) => Promise<void>
24
+ clear: () => Promise<void>
25
+ show: () => Promise<void>
26
+ hide: () => Promise<void>
27
+ onAction: (cb: (event: TouchBarActionEvent) => void) => () => void
28
+ }
29
+ export type TouchBarItemType = 'button' | 'label' | 'slider' | 'spacer' | 'colorPicker' | 'segmented';