@bobfrankston/msgapidefs 0.1.30 → 0.1.31

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
@@ -1,7 +1,24 @@
1
1
  # @bobfrankston/msgapidefs
2
2
 
3
- TypeScript definitions for the **msgapi** JavaScript API used in msgview and msger. See the Typescript definitions in
4
- [msgdpidefs.ts](msgapidefs.ts) for more info
3
+ > **⚠️ SECURITY:** msgapi gives full native OS access (filesystem, processes, networking). Intended ONLY for trusted apps native apps written as web pages. Do not expose to untrusted content.
4
+
5
+ > **⚠️ EXPERIMENTAL:** APIs are experimental and subject to change.
6
+
7
+ TypeScript definitions for the **msgapi** JavaScript API used by msga, msger, and msgview. See the Typescript definitions in
8
+ [msgapidefs.ts](msgapidefs.ts) for more info
9
+
10
+ ## Workspace Structure
11
+
12
+ ```
13
+ msgx (workspace root)
14
+ ├── msgapidefs - TypeScript type definitions for window.msgapi (this package)
15
+ ├── msgcommon - Shared CLI parsing, templates, pinning utilities
16
+ ├── msger - Rust/wry webview host (Windows, Linux)
17
+ ├── msgview - Electron webview host (Windows, Linux, Mac, Pi)
18
+ ├── msga - .NET MAUI webview host (Android, Windows)
19
+ ├── build - Release build orchestration script (build/build.ts)
20
+ └── md - Shared documentation
21
+ ```
5
22
 
6
23
  ## Installation
7
24
 
@@ -35,6 +52,23 @@ localStorage.setItem('key', 'value'); // Instead of msgapi.saveData()
35
52
  window.close(); // Instead of msgapi.close() if not passing result
36
53
  ```
37
54
 
55
+ ## Platform Support
56
+
57
+ ✅ = Current | 🔧 = Possible (recompile/rebuild needed) | ❌ = Not feasible
58
+
59
+ | Platform | msger (Rust/wry) | msgview (Electron) | msga (.NET MAUI) |
60
+ |----------|:----------------:|:------------------:|:----------------:|
61
+ | **Windows** | ✅ | ✅ | ✅ |
62
+ | **Linux** | ✅ | ✅ | ❌ |
63
+ | **macOS** | 🔧 wry supports it | ✅ | 🔧 Mac Catalyst |
64
+ | **Raspberry Pi** | ⚠️ runs but no display | ✅ | ❌ |
65
+ | **Android** | ❌ | ❌ | ✅ (primary) |
66
+ | **iOS** | ❌ | ❌ | ❌ |
67
+
68
+ > **msger** uses wry (Rust webview). Desktop platforms (Win/Linux/Mac) are mature. msger can cross-compile and run on the Pi but does not display properly (wry/GTK rendering issues) — not a priority to fix.
69
+ > **msgview** runs wherever Electron does — desktop only, no mobile.
70
+ > **msga** targets Android primarily; Windows for dev/testing. **iOS** would be the most realistic path — MAUI supports iOS natively, so msga could target it with an iOS build profile, Apple developer account, and platform-specific conditional code (`#if IOS`) for permissions and APIs. No current plans.
71
+
38
72
  ## Implementation Status
39
73
 
40
74
  ✅ = Implemented | ⚠️ = Partial | ❌ = Not implemented
@@ -46,33 +80,41 @@ window.close(); // Instead of msgapi.close() if not passing result
46
80
  | `setLogging(value?)` | ❌ | ❌ | ✅ | Returns previous state |
47
81
  | `setAutoUpdate(value?)` | ❌ | ❌ | ✅ | `'auto'`/`'check'`/`'off'`; msga Android only |
48
82
  | **Window Control** | | | | **`window.msgapi.*`** |
49
- | `toggleFullscreen()` | ❌ | ⚠️ | ✅ | msger: via IPC, not on window.msgapi |
50
- | `setFullscreen(bool)` | ✅ | ⚠️ | ✅ | msger: via IPC, not on window.msgapi |
51
- | `minimize()` | ✅ | ⚠️ | ✅ | msga: Windows only; msger: via IPC |
52
- | `maximize()` | ✅ | ⚠️ | ✅ | msga: Windows only; msger: via IPC |
53
- | `setSize(w, h)` | ✅ | ⚠️ | ✅ | msga: Windows only; msger: via IPC |
54
- | `setPosition(x, y)` | ✅ | ⚠️ | ✅ | msga: Windows only; msger: via IPC |
55
- | `setAlwaysOnTop(bool)` | ✅ | ⚠️ | ❌ | msger: via IPC |
56
- | `close(result?)` | ✅ | ✅ | ✅ | msger: on window.msger |
83
+ | `toggleFullscreen()` | ❌ | | ✅ | msger: via `window.msgapi` (msger-api.js) |
84
+ | `setFullscreen(bool)` | ✅ | | ✅ | |
85
+ | `minimize()` | ✅ | | ✅ | msga: Windows only |
86
+ | `maximize()` | ✅ | | ✅ | msga: Windows only |
87
+ | `setSize(w, h)` | ✅ | | ✅ | msga: Windows only |
88
+ | `setPosition(x, y)` | ✅ | | ✅ | msga: Windows only |
89
+ | `setAlwaysOnTop(bool)` | ✅ | | ❌ | |
90
+ | `close(result?)` | ✅ | ✅ | ✅ | |
57
91
  | `navigate(url)` | ❌ | ❌ | ✅ | msga only |
58
92
  | `reload()` | ❌ | ❌ | ✅ | msga only |
59
93
  | **File System** | | | | **`window.msgapi.fs.*`** |
60
- | `fs.selectFile()` | | | ⚠️ | msga: C# exists, not wired to JS |
61
- | `fs.selectFiles()` | | | ⚠️ | msga: C# exists, not wired to JS |
62
- | `fs.saveFileAs()` | | | | |
63
- | `fs.selectFolder()` | | | | |
64
- | `fs.read(path)` | | | | Requires allowFs flag |
65
- | `fs.write(path, content)` | | | | Requires allowFs flag |
66
- | `fs.list(path)` | | | | Requires allowFs flag |
67
- | `fs.exists(path)` | | | | Requires allowFs flag |
68
- | `fs.delete(path)` | | | | Requires allowFs flag |
94
+ | `fs.selectFile()` | | | | msga: full JS bridge wired |
95
+ | `fs.selectFiles()` | | | | msga: full JS bridge wired |
96
+ | `fs.saveFileAs()` | | | | msga: Windows only |
97
+ | `fs.selectFolder()` | | | | msga: Windows only |
98
+ | `fs.read(path)` | | | | msga: binary→base64→TextDecoder |
99
+ | `fs.readAsDataUrl(path)` | | | | msga: auto-detects MIME from extension |
100
+ | `fs.write(path, content)` | | | | |
101
+ | `fs.list(path)` | | | | msga: includes attributes/created on Windows |
102
+ | `fs.exists(path)` | | | | |
103
+ | `fs.delete(path)` | ❌ | ❌ | ✅ | |
104
+ | **Shell** | | | | **`window.msgapi.shell.*`** |
105
+ | `shell.exec()` | ❌ | ❌ | ✅ | Process with stdout/stderr; limited on non-rooted Android |
106
+ | `shell.open()` | ❌ | ❌ | ✅ | Android: Intent.ACTION_VIEW; Windows: ShellExecute |
107
+ | `shell.showInFolder()` | ❌ | ❌ | ❌ | Defined in interface, not yet implemented |
108
+ | `shell.trash()` | ❌ | ❌ | ❌ | Defined in interface, not yet implemented |
69
109
  | **UDP Networking** | | | | **`window.msgapi.udp.*`** |
70
- | `udp.send()` | | | ✅ | msga: C# UdpClient |
71
- | `udp.listen()` | | | ✅ | msga: background receive loop |
72
- | `udp.sendReceive()` | | | ✅ | msga: send + wait with timeout |
73
- | `udp.broadcast()` | | | ✅ | msga: EnableBroadcast=true |
110
+ | `udp.send()` | | | ✅ | Node dgram / Rust UdpSocket / C# UdpClient |
111
+ | `udp.listen()` | | | ✅ | Background receive loop in all hosts |
112
+ | `udp.sendReceive()` | | | ✅ | Send + wait with timeout |
113
+ | `udp.broadcast()` | | | ✅ | 255.255.255.255 broadcast |
114
+ | **HTTP Fetch** | | | | **`window.msgapi.http.*`** |
115
+ | `http.fetch()` | ✅ | ✅ | ✅ | Native HTTP — bypasses CORS/mixed-content |
74
116
 
75
- > **msger note:** Window control functionality exists in Rust but is exposed via `window.msger` + IPC actions (`window.ipc.postMessage({_action: ...})`), not as `window.msgapi` methods. Alignment to `window.msgapi` is needed.
117
+ > **msger** now injects `window.msgapi` via `msger-api.js` with window control, UDP, and HTTP. File system and shell are not yet implemented in msger or msgview.
76
118
 
77
119
  [httpudp-client](../../homecontrol/utils/udp/httpudp-client/README.md) auto-detects `window.msgapi?.udp` and uses native UDP when available, falling back to the httpudp WebSocket proxy otherwise.
78
120
 
@@ -117,14 +159,15 @@ File dialogs (user picks interactively — safe without special permissions):
117
159
  - `fs.saveFileAs(content, filename?, options?)` - Save file dialog
118
160
  - `fs.selectFolder(options?)` - Folder picker
119
161
 
120
- Direct path operations (give the webview full filesystem access):
121
- - `fs.read(path)` - Read file
162
+ Direct path operations (give the webview full filesystem access — msga only currently):
163
+ - `fs.read(path, options?)` - Read file. Options: `{ encoding: 'utf8' | 'base64' | 'binary' }`. Default `'utf8'` returns string; `'base64'` returns raw base64 string (efficient for images); `'binary'` returns `Uint8Array`.
164
+ - `fs.readAsDataUrl(path, mimeType?)` - Read file as data URL (`data:image/jpeg;base64,...`). Auto-detects MIME from extension if omitted.
122
165
  - `fs.write(path, content)` - Write file
123
- - `fs.list(path)` - List directory
124
- - `fs.exists(path)` - Check if file exists
125
- - `fs.delete(path)` - Delete file
166
+ - `fs.list(path)` - List directory. Returns `FileInfo[]` with `attributes` (Win32 flags) and `created` on Windows.
167
+ - `fs.exists(path)` - Check if file/directory exists
168
+ - `fs.delete(path)` - Delete file or directory
126
169
 
127
- > **`allowFs` flag:** Direct path operations are intended to require an explicit `--allowFs` CLI flag (e.g., `msger -url "..." --allowFs`) since they grant unrestricted filesystem access. This flag is documented in the interface but **not yet enforced** the methods currently work without it in both msger and msgview. Enforcement is planned.
170
+ > **Note:** File system operations are currently implemented only in msga. msger and msgview do not yet have `window.msgapi.fs` these hosts have their own internal fs mechanisms but have not wired them to the msgapi interface.
128
171
 
129
172
  ### UDP Networking
130
173
 
@@ -135,6 +178,38 @@ Native UDP socket access — no WebSocket proxy needed when running inside a msg
135
178
  - `udp.sendReceive(host, port, data, timeoutMs?)` - Send and wait for response
136
179
  - `udp.broadcast(port, data)` - Broadcast to local network
137
180
 
181
+ ### Shell / Process Execution
182
+
183
+ Native process execution — run commands, open files with default handler. msga only currently.
184
+
185
+ - `shell.exec(command, args?, options?)` - Run external command and capture output. Returns `{ stdout, stderr, exitCode }`. Options: `cwd`, `timeout` (ms), `stdin`, `encoding` (`'utf8'`|`'base64'`). Limited on non-rooted Android.
186
+ - `shell.open(path)` - Open file/URL with system default handler (Windows: ShellExecute, Android: Intent.ACTION_VIEW)
187
+ - `shell.showInFolder(path)` - Select file in Explorer / file manager (not yet implemented)
188
+ - `shell.trash(path)` - Move to Recycle Bin / Trash (not yet implemented)
189
+
190
+ ### HTTP Fetch
191
+
192
+ Native HTTP client — bypasses browser CORS and mixed-content restrictions. Use when an HTTPS-served web app needs to reach HTTP endpoints (e.g., local devices on the LAN).
193
+
194
+ - `http.fetch(url, init?)` - Drop-in replacement for browser `fetch()`. Same `RequestInit` params, returns a real `Response` object (`.ok`, `.status`, `.json()`, `.text()`, `.headers`, `.clone()`, etc.)
195
+
196
+ ```javascript
197
+ // HTTP from an HTTPS page — blocked by browsers, works via msgapi
198
+ const r = await window.msgapi.http.fetch('http://192.168.1.5/api/status');
199
+ const data = await r.json();
200
+
201
+ // POST with headers and body
202
+ const r2 = await window.msgapi.http.fetch('http://192.168.1.5/api/cmd', {
203
+ method: 'POST',
204
+ headers: { 'Content-Type': 'application/json' },
205
+ body: JSON.stringify({ cmd: 'reboot' })
206
+ });
207
+ ```
208
+
209
+ **Platform implementations:** msga uses C# `HttpClient`, msger uses Rust `ureq`, msgview uses Node.js `fetch()`. All return a real `Response` object constructed on the JS side.
210
+
211
+ **Unsupported `init` fields** (silently ignored — not meaningful for native HTTP): `mode`, `credentials`, `cache`, `signal`, `redirect`. `new Headers()` objects are normalized to plain objects.
212
+
138
213
  ## Examples
139
214
 
140
215
  See [samples.html](samples.html) for interactive examples and demos of all API features!
@@ -174,9 +249,9 @@ The samples demonstrate:
174
249
 
175
250
  ### msger (Rust/wry)
176
251
  - **Bridge:** JavaScript injected via wry `with_initialization_script()` in `msger-native/src/main.rs`
177
- - **JS API:** `msger-native/src/msger-api.js` creates `window.msger` object
252
+ - **JS API:** `msger-native/src/msger-api.js` creates `window.msgapi` object
178
253
  - **Mechanism:** `window.ipc.postMessage(JSON.stringify(...))` to Rust IPC handler
179
- - **Note:** Currently exposes `window.msger` (not `window.msgapi`) - alignment needed
254
+ - **Capabilities:** Window control, UDP, HTTP fetch via `window.msgapi`
180
255
  - **Limitations:** wry 0.47.2 has IPC issues; `close()` uses `window.close()` workaround
181
256
 
182
257
  ### msga (.NET MAUI)
package/msgapi-plan.md CHANGED
@@ -14,7 +14,7 @@ Shared planning document for msgapi across implementations:
14
14
  | API | msgview | msger | msga | Notes |
15
15
  |-----|---------|-------|------|-------|
16
16
  | **Window Control** |
17
- | toggleFullscreen() | | ✅ | ✅ | msga: fire-and-forget JS→C# |
17
+ | toggleFullscreen() | | ✅ | ✅ | msga: fire-and-forget JS→C# |
18
18
  | setFullscreen(bool) | ✅ | ✅ | ✅ | |
19
19
  | minimize() | ✅ | ✅ | ✅ | msga: Windows only |
20
20
  | maximize() | ✅ | ✅ | ✅ | msga: Windows only |
@@ -25,22 +25,30 @@ Shared planning document for msgapi across implementations:
25
25
  | navigate(url) | ❌ | ❌ | ✅ | msga only |
26
26
  | reload() | ❌ | ❌ | ✅ | msga only |
27
27
  | **File System** |
28
- | fs.selectFile() | | | ⚠️ | msga: C# exists, not wired |
29
- | fs.selectFiles() | | | ⚠️ | msga: C# exists, not wired |
30
- | fs.saveFileAs() | | | | |
31
- | fs.selectFolder() | | | | |
32
- | fs.read(path) | | | | Requires allowFs flag |
33
- | fs.write(path) | | | | Requires allowFs flag |
34
- | fs.list(path) | | | | Requires allowFs flag |
35
- | fs.exists(path) | | | | Requires allowFs flag |
36
- | fs.delete(path) | | | | Requires allowFs flag |
28
+ | fs.selectFile() | | | | msga: full JS bridge wired |
29
+ | fs.selectFiles() | | | | msga: full JS bridge wired |
30
+ | fs.saveFileAs() | | | | msga: Windows only |
31
+ | fs.selectFolder() | | | | msga: Windows only |
32
+ | fs.read(path, options?) | | | | encoding: utf8/base64/binary |
33
+ | fs.readAsDataUrl(path) | | | | Auto-detects MIME from extension |
34
+ | fs.write(path) | | | | |
35
+ | fs.list(path) | | | | Includes attributes/created on Windows |
36
+ | fs.exists(path) | | | | |
37
+ | fs.delete(path) | ❌ | ❌ | ✅ | |
38
+ | **Shell** |
39
+ | shell.exec() | ❌ | ❌ | ✅ | Process with stdout/stderr; limited on non-rooted Android |
40
+ | shell.open() | ❌ | ❌ | ✅ | Android: Intent.ACTION_VIEW; Windows: ShellExecute |
41
+ | shell.showInFolder() | ❌ | ❌ | ❌ | Defined in interface, not yet implemented |
42
+ | shell.trash() | ❌ | ❌ | ❌ | Defined in interface, not yet implemented |
37
43
  | **UDP** |
38
- | udp.send() | | | ✅ | msga: C# UdpClient |
39
- | udp.listen() | | | ✅ | msga: background receive loop |
40
- | udp.sendReceive() | | | ✅ | msga: send + wait with timeout |
41
- | udp.broadcast() | | | ✅ | msga: EnableBroadcast=true |
44
+ | udp.send() | | | ✅ | Node dgram / Rust UdpSocket / C# UdpClient |
45
+ | udp.listen() | | | ✅ | Background receive loop in all hosts |
46
+ | udp.sendReceive() | | | ✅ | Send + wait with timeout |
47
+ | udp.broadcast() | | | ✅ | 255.255.255.255 broadcast |
48
+ | **HTTP** |
49
+ | http.fetch() | ✅ | ✅ | ✅ | CORS/mixed-content bypass via native HTTP; returns real Response object |
42
50
  | **Configuration** |
43
- | setLogging(value?) | ❌ | ❌ | ✅ | Returns old state; 'msga'/'msgapi'/'on'/'off'/null |
51
+ | setLogging(value?, name?) | ❌ | ❌ | ✅ | Returns old state; 'msga'/'msgapi'/'on'/'off'/null; name included in log messages/filenames |
44
52
  | setAutoUpdate(value?) | ❌ | ❌ | ✅ | 'auto'/'check'/'off'; defaults to 'off' (web app owns policy) |
45
53
  | installUpdate(url) | ❌ | ❌ | ✅ | Download + install APK; Android only. Web app calls this. |
46
54
  | getNetworkInfo() | ❌ | ❌ | ✅ | Fresh local IP + subnet mask; used by httpudp-client isAddressReachable() |
@@ -48,7 +56,7 @@ Shared planning document for msgapi across implementations:
48
56
  | updateUrl | ❌ | ❌ | ✅ | URL to versions.json — install source for update checks |
49
57
  | version | ❌ | ❌ | ✅ | `window.msgapi.version` = app version string |
50
58
 
51
- Legend: ✅ Implemented | ⚠️ Partial/Not wired | ❌ Not implemented
59
+ Legend: ✅ Implemented | ❌ Not implemented
52
60
 
53
61
  ### msga Logging
54
62
 
@@ -56,18 +64,20 @@ Two independent log streams, both via `https://rmf39.aaz.lt/logit/`:
56
64
 
57
65
  | Stream | Log name | Controlled by | Content |
58
66
  |--------|----------|---------------|---------|
59
- | **C# (MsgALog)** | `logit-msga` | `LOGGING=true` in msga.env | OnNavigated, msgapi:// dispatch, SendAsync, UDP recv |
60
- | **JS (_logit)** | `logit-msgapi` | `JS_LOGGING=true` in msga.env | msgapi inject, msgapi object creation |
67
+ | **C# (MsgALog)** | `logit-msga` | `LOGGING=false` in msga.env | OnNavigated, msgapi:// dispatch, SendAsync, UDP recv |
68
+ | **JS (_logit)** | `logit-msgapi` | `JS_LOGGING=false` in msga.env | msgapi inject, msgapi object creation |
61
69
 
62
- **Startup defaults** are set in `msga.env`. At **runtime**:
70
+ **Startup defaults** are `false` in `msga.env` — logging is off unless the web app enables it. At **runtime**:
63
71
  ```javascript
64
- msgapi.setLogging() // → 'none' (query current, no change)
65
- msgapi.setLogging('msga') // 'none' (old); enables C# only
66
- msgapi.setLogging('msgapi') // 'msga' (old); enables JS only
67
- msgapi.setLogging('on') // 'msgapi' (old); enables both
68
- msgapi.setLogging('off') // 'msga,msgapi' (old); disables both
72
+ msgapi.setLogging() // → 'none' (query current, no change)
73
+ msgapi.setLogging('on') // enables both C# and JS logging
74
+ msgapi.setLogging('on', 'test') // enables both; C# logs to logit-msga-test, JS to logit-msgapi-test, 'test' in messages
75
+ msgapi.setLogging('msga') // enables C# only
76
+ msgapi.setLogging('msgapi') // enables JS only
77
+ msgapi.setLogging('off') // disables both
69
78
  ```
70
79
  Always returns previous state as string: `'msga'`, `'msgapi'`, `'msga,msgapi'`, or `'none'`.
80
+ The optional `name` parameter is included in: log file names (`logit-msga-{name}`, `logit-msgapi-{name}`) and C# log message prefix.
71
81
 
72
82
  ### msga Implementation Status
73
83
 
@@ -95,10 +105,15 @@ interface MsgAPI {
95
105
  }
96
106
  ```
97
107
 
98
- **Platform implementations**:
108
+ **Platform implementations (UDP)**:
99
109
  - **msga** (C#/MAUI): ✅ `System.Net.Sockets.UdpClient` via `UdpService.cs`
100
- - **msgview** (Electron): Planned — Node.js `dgram` via IPC/preload
101
- - **msger** (Rust/wry): Planned — `std::net::UdpSocket` or tokio
110
+ - **msgview** (Electron): Node.js `dgram` via `ipcMain.handle` / preload
111
+ - **msger** (Rust/wry): `std::net::UdpSocket` via `NativeEvent` + event loop
112
+
113
+ **Platform implementations (HTTP fetch)**:
114
+ - **msga** (C#/MAUI): ✅ `HttpClient` — static instance, async `SendAsync`
115
+ - **msgview** (Electron): ✅ Node.js `fetch()` via `ipcMain.handle`
116
+ - **msger** (Rust/wry): ✅ `ureq` crate — blocking in `std::thread::spawn`, results via event loop
102
117
 
103
118
  **httpudp-client integration**: `HttpUdpClient.connect()` detects `window.msgapi?.udp` and uses it directly when available, falling back to the httpudp WebSocket proxy otherwise. Callers never know which path was taken.
104
119
 
@@ -225,19 +240,26 @@ interface MsgAPI {
225
240
  4. ✅ UDP fully implemented in msga (UdpService.cs)
226
241
  5. ✅ httpudp-client detects msgapi.udp and uses it natively
227
242
 
228
- ### Phase 2: UDP in msger/msgview
229
- 1. Implement in msger (Rust) — `std::net::UdpSocket` or tokio
230
- 2. Port to msgview (Electron) — Node.js `dgram` via IPC/preload
243
+ ### Phase 2: UDP in msger/msgview ✅ Done
244
+ 1. msger (Rust) — `std::net::UdpSocket` via NativeEvent + thread::spawn
245
+ 2. msgview (Electron) — Node.js `dgram` via ipcMain.handle + preload
246
+
247
+ ### Phase 3: File System + Shell in msga ✅ Done
248
+ 1. ✅ fs.read with encoding options (utf8/base64/binary)
249
+ 2. ✅ fs.readAsDataUrl with MIME auto-detection
250
+ 3. ✅ fs.list with attributes/created on Windows
251
+ 4. ✅ shell.exec — process execution with stdout/stderr capture
252
+ 5. ✅ shell.open — open files/URLs with system default handler
231
253
 
232
- ### Phase 3: Enhanced File System
233
- 1. Add new fs types to msgapidefs
234
- 2. Implement mkdir, rename, copy, stat
235
- 3. Add file watching (platform-specific)
254
+ ### Phase 4: File System + Shell in msger/msgview
255
+ 1. Implement fs.* via msgcommon shared code
256
+ 2. Implement shell.exec/open via msgcommon shared code
257
+ 3. Add mkdir, rename, copy, stat extensions
236
258
 
237
- ### Phase 4: System Integration
259
+ ### Phase 5: System Integration (Lower Priority)
238
260
  1. Clipboard support
239
261
  2. Notifications
240
- 3. Platform detection
262
+ 3. shell.showInFolder, shell.trash
241
263
 
242
264
  ---
243
265
 
package/msgapidefs.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  // TypeScript definitions for the msgapi JavaScript API
2
- // Type-safe access to msgapi's window control, file system, and UDP features
2
+ // Type-safe access to msgapi's window control, file system, shell, and UDP features
3
3
  // Used by msgview, msger, and msga. See README.md for docs.
4
+ //
5
+ // ⚠️ SECURITY: msgapi gives full native OS access (filesystem, processes, networking).
6
+ // Intended ONLY for trusted apps — native apps written as web pages. Do not expose to untrusted content.
7
+ // ⚠️ EXPERIMENTAL: APIs are experimental and subject to change.
4
8
 
5
9
  export interface MsgResult { // Result object returned when the window closes
6
10
  button: string; // Button that was clicked
@@ -17,6 +21,8 @@ export interface FileInfo { // File information from file system operations
17
21
  isDir: boolean; // True if this is a directory
18
22
  size: number; // File size in bytes (0 for directories)
19
23
  modified?: string; // Last modified timestamp (ISO 8601 string)
24
+ created?: string; // Creation time (ISO 8601 string); undefined on platforms without creation time
25
+ attributes?: number; // Win32 FILE_ATTRIBUTE_* flags (e.g. 0x00400000 = RECALL_ON_DATA_ACCESS for OneDrive cloud-only); undefined on Android/Linux
20
26
  }
21
27
 
22
28
  export interface FileDialogOptions { // Options for file selection dialogs
@@ -74,7 +80,7 @@ export interface MsgAPI {
74
80
 
75
81
  // ── Configuration ────────────────────────────────────────────
76
82
 
77
- setLogging?(value?: LoggingMode): LoggingMode; // null/undefined = query only. Returns previous state.
83
+ setLogging?(value?: LoggingMode, name?: string): LoggingMode; // null/undefined = query only. name included in log messages/filenames. Returns previous state.
78
84
  setAutoUpdate?(value?: AutoUpdateMode): AutoUpdateMode; // null/undefined = query only. Returns previous state. msga Android only.
79
85
  installUpdate?(url: string): Promise<void>; // Download + install APK from url. msga Android only; web app owns update policy.
80
86
  getNetworkInfo?(): Promise<{ localIp: string; localMask: string }>; // Current device IP + subnet mask (fresh, not cached)
@@ -97,7 +103,8 @@ export interface MsgAPI {
97
103
  selectFiles(options?: FileDialogOptions): Promise<SelectedFile[]>; // Multi-file picker
98
104
  saveFileAs(content: string, defaultFilename?: string, options?: FileDialogOptions): Promise<string | null>; // Save dialog (returns path or null)
99
105
  selectFolder(options?: FileDialogOptions): Promise<string | null>; // Folder picker (null if cancelled)
100
- read(path: string): Promise<string>; // Read file contents (requires allowFs)
106
+ read(path: string, options?: { encoding?: 'utf8' | 'base64' | 'binary' }): Promise<string | Uint8Array>; // Read file; utf8 (default)=text, base64=raw b64 string, binary=Uint8Array
107
+ readAsDataUrl(path: string, mimeType?: string): Promise<string>; // Read file as data URL (auto-detects MIME from extension if omitted)
101
108
  write(path: string, content: string): Promise<void>; // Write file contents (requires allowFs)
102
109
  list(path: string): Promise<FileInfo[]>; // List directory contents (requires allowFs)
103
110
  exists(path: string): Promise<boolean>; // Check if file/directory exists (requires allowFs)
@@ -113,6 +120,30 @@ export interface MsgAPI {
113
120
  sendReceive(host: string, port: number, data: string | Uint8Array, timeoutMs?: number): Promise<Uint8Array>; // Send and wait for response
114
121
  broadcast(port: number, data: string | Uint8Array): Promise<void>; // Broadcast to local network
115
122
  };
123
+
124
+ // ── HTTP Fetch (CORS/mixed-content bypass) ──────────────────
125
+ // Routes requests through the native host — no mixed-content or CORS restrictions
126
+ // Returns a real Response object: .ok, .status, .json(), .text(), .headers, .clone()
127
+
128
+ http?: {
129
+ fetch(url: string, init?: RequestInit): Promise<Response>; // Drop-in fetch() replacement via native HTTP
130
+ };
131
+
132
+ // ── Shell / Process Execution ─────────────────────────────────
133
+ // Native process execution — run commands, open files with default handler
134
+ // ⚠️ Powerful: grants full process execution. Use only in trusted apps.
135
+
136
+ shell?: {
137
+ exec(command: string, args?: string[], options?: { // Run external command, capture output
138
+ cwd?: string; // Working directory
139
+ timeout?: number; // Timeout in ms (0 = no timeout)
140
+ stdin?: string; // Pipe string to stdin
141
+ encoding?: 'utf8' | 'base64'; // stdout/stderr encoding (default utf8)
142
+ }): Promise<{ stdout: string; stderr: string; exitCode: number }>;
143
+ open(path: string): Promise<void>; // Open file/URL with system default handler (ShellExecute / Intent.ACTION_VIEW)
144
+ showInFolder(path: string): Promise<void>; // Select file in Explorer / file manager
145
+ trash(path: string): Promise<void>; // Move to Recycle Bin / Trash (soft delete, not permanent)
146
+ };
116
147
  }
117
148
 
118
149
  // Global window.msgapi declaration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/msgapidefs",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "TypeScript definitions for msgapi JavaScript API (msgview/msger)",
5
5
  "type": "module",
6
6
  "main": "./msgapidefs.js",