@bobfrankston/msgapidefs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @bobfrankston/msgapidefs
2
+
3
+ TypeScript definitions for the **msgapi** JavaScript API used in msgview and msger.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @bobfrankston/msgapidefs
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### TypeScript
14
+
15
+ ```typescript
16
+ import type { MsgAPI } from '@bobfrankston/msgapidefs';
17
+ import { isMsgAPI, getMsgAPI } from '@bobfrankston/msgapidefs';
18
+
19
+ // Option 1: Type the global window.msgapi
20
+ declare global {
21
+ interface Window {
22
+ msgapi?: MsgAPI;
23
+ }
24
+ }
25
+
26
+ // Check if running in msgview/msger
27
+ if (isMsgAPI()) {
28
+ window.msgapi!.setTitle('My Application');
29
+ window.msgapi!.saveData('lastOpened', new Date().toISOString());
30
+ }
31
+
32
+ // Option 2: Use getMsgAPI() for cross-platform compatibility
33
+ const msgapi = getMsgAPI();
34
+ msgapi.saveData('userPrefs', { theme: 'dark' }); // Works in both msgview/msger and browser!
35
+ msgapi.setTitle('My App'); // Only works in msgview/msger, no-op in browser
36
+ ```
37
+
38
+ ### JavaScript
39
+
40
+ ```javascript
41
+ import { isMsgAPI, getMsgAPI } from '@bobfrankston/msgapidefs';
42
+
43
+ const msgapi = getMsgAPI();
44
+
45
+ // Data persistence (works in both msgview/msger and browser)
46
+ msgapi.saveData('userSettings', { fontSize: 14, theme: 'dark' });
47
+ const settings = msgapi.loadData('userSettings', { fontSize: 12 });
48
+
49
+ // Window control (msgview/msger only, gracefully degrades in browser)
50
+ if (isMsgAPI()) {
51
+ msgapi.toggleFullscreen();
52
+ msgapi.setAlwaysOnTop(true);
53
+ }
54
+ ```
55
+
56
+ ## API Reference
57
+
58
+ ### Window Control
59
+
60
+ - `toggleFullscreen()` - Toggle fullscreen mode
61
+ - `setFullscreen(enabled: boolean)` - Set fullscreen state
62
+ - `minimize()` - Minimize window
63
+ - `maximize()` - Toggle maximize/restore
64
+ - `setSize(width, height)` - Set window size
65
+ - `setPosition(x, y)` - Set window position
66
+ - `setAlwaysOnTop(enabled: boolean)` - Keep window on top
67
+ - `setTitle(title: string)` - Set window title
68
+ - `close(result?)` - Close window with optional result
69
+
70
+ ### Data Persistence
71
+
72
+ - `saveData(key, value)` - Save data to localStorage
73
+ - `loadData(key, defaultValue?)` - Load data from localStorage
74
+ - `removeData(key)` - Remove data
75
+ - `clearData()` - Clear all msgapi data
76
+
77
+ ### File System (Coming Soon)
78
+
79
+ - `fs.selectFile(options?)` - Open file picker
80
+ - `fs.selectFiles(options?)` - Open multi-file picker
81
+ - `fs.saveFileAs(content, filename?, options?)` - Save file dialog
82
+ - `fs.selectFolder(options?)` - Folder picker
83
+ - `fs.read(path)` - Read file (requires allowFs flag)
84
+ - `fs.write(path, content)` - Write file (requires allowFs flag)
85
+ - `fs.list(path)` - List directory (requires allowFs flag)
86
+ - `fs.exists(path)` - Check if file exists (requires allowFs flag)
87
+ - `fs.delete(path)` - Delete file (requires allowFs flag)
88
+
89
+ ## Examples
90
+
91
+ See [samples.html](samples.html) for interactive examples and demos of all API features!
92
+
93
+ **Test in msgview:**
94
+ ```bash
95
+ msgview -url "file:///path/to/node_modules/@bobfrankston/msgapidefs/samples.html"
96
+ ```
97
+
98
+ **Test in msger:**
99
+ ```bash
100
+ msger -url "file:///path/to/node_modules/@bobfrankston/msgapidefs/samples.html"
101
+ ```
102
+
103
+ **Test in browser:**
104
+ ```bash
105
+ # Open samples.html in your browser to test browser compatibility
106
+ ```
107
+
108
+ The samples demonstrate:
109
+ - Window control (fullscreen, minimize, maximize, resize, position)
110
+ - Data persistence (save/load user preferences, session data, recent files)
111
+ - Presentation mode example
112
+ - Session management
113
+ - And more!
114
+
115
+ ## Browser Compatibility
116
+
117
+ The `getMsgAPI()` function returns a browser-compatible implementation:
118
+
119
+ - **Data persistence**: Uses localStorage in both msgview/msger and browser
120
+ - **Window control**: No-op in browser (except `setTitle` updates document.title)
121
+ - **File system**: Not available in browser (`fs` is undefined)
122
+
123
+ This allows you to write code once that works in both environments!
124
+
125
+ ## Related Packages
126
+
127
+ - [@bobfrankston/msgview](https://www.npmjs.com/package/@bobfrankston/msgview) - Electron-based message box (slower, works on Pi)
128
+ - [@bobfrankston/msger](https://www.npmjs.com/package/@bobfrankston/msger) - Rust/wry-based message box (fast, lightweight)
129
+
130
+ ## License
131
+
132
+ ISC
@@ -0,0 +1,322 @@
1
+ /**
2
+ * TypeScript definitions for the msgapi JavaScript API
3
+ *
4
+ * This module provides type-safe access to msgapi's window control,
5
+ * data persistence, and file system features (used by msgview and msger).
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import type { MsgAPI } from '@bobfrankston/msgapidefs';
10
+ *
11
+ * declare global {
12
+ * interface Window {
13
+ * msgapi?: MsgAPI;
14
+ * }
15
+ * }
16
+ *
17
+ * // Check if running in msgview/msger
18
+ * if (window.msgapi) {
19
+ * window.msgapi.setTitle('My App');
20
+ * }
21
+ * ```
22
+ */
23
+ /**
24
+ * Result object returned when the window closes
25
+ */
26
+ export interface MsgResult {
27
+ /** Button that was clicked */
28
+ button: string;
29
+ /** Optional input field value */
30
+ value?: string;
31
+ /** Optional form data */
32
+ form?: Record<string, any>;
33
+ /** True if window was closed via close button */
34
+ closed?: boolean;
35
+ /** True if window was dismissed via Escape key */
36
+ dismissed?: boolean;
37
+ /** True if window was closed due to timeout */
38
+ timeout?: boolean;
39
+ }
40
+ /**
41
+ * File information returned by file system operations
42
+ */
43
+ export interface FileInfo {
44
+ /** File name */
45
+ name: string;
46
+ /** Full file path */
47
+ path: string;
48
+ /** True if this is a directory */
49
+ isDir: boolean;
50
+ /** File size in bytes (0 for directories) */
51
+ size: number;
52
+ /** Last modified timestamp (ISO 8601 string) */
53
+ modified?: string;
54
+ }
55
+ /**
56
+ * Options for file selection dialogs
57
+ */
58
+ export interface FileDialogOptions {
59
+ /** Dialog title */
60
+ title?: string;
61
+ /** Default filename for save dialogs */
62
+ defaultFilename?: string;
63
+ /** File filters (e.g., [{name: "Text", extensions: ["txt", "md"]}]) */
64
+ filters?: Array<{
65
+ name: string;
66
+ extensions: string[];
67
+ }>;
68
+ /** Default directory to open */
69
+ defaultPath?: string;
70
+ }
71
+ /**
72
+ * Selected file with content
73
+ */
74
+ export interface SelectedFile {
75
+ /** File name */
76
+ name: string;
77
+ /** Full file path */
78
+ path: string;
79
+ /** File content as string */
80
+ content: string;
81
+ }
82
+ /**
83
+ * msgapi JavaScript API
84
+ *
85
+ * Available when running inside msgview/msger via window.msgapi
86
+ */
87
+ export interface MsgAPI {
88
+ /**
89
+ * Toggle fullscreen mode on/off
90
+ * @example
91
+ * msgapi.toggleFullscreen();
92
+ */
93
+ toggleFullscreen(): void;
94
+ /**
95
+ * Set fullscreen mode
96
+ * @param enabled - true to enter fullscreen, false to exit
97
+ * @example
98
+ * msgapi.setFullscreen(true);
99
+ */
100
+ setFullscreen(enabled: boolean): void;
101
+ /**
102
+ * Minimize the window
103
+ * @example
104
+ * msgapi.minimize();
105
+ */
106
+ minimize(): void;
107
+ /**
108
+ * Toggle maximize/restore window
109
+ * @example
110
+ * msgapi.maximize();
111
+ */
112
+ maximize(): void;
113
+ /**
114
+ * Set window size
115
+ * @param width - Window width in pixels
116
+ * @param height - Window height in pixels
117
+ * @example
118
+ * msgapi.setSize(800, 600);
119
+ */
120
+ setSize(width: number, height: number): void;
121
+ /**
122
+ * Set window position
123
+ * @param x - X coordinate in pixels
124
+ * @param y - Y coordinate in pixels
125
+ * @example
126
+ * msgapi.setPosition(100, 100);
127
+ */
128
+ setPosition(x: number, y: number): void;
129
+ /**
130
+ * Set always-on-top behavior
131
+ * @param enabled - true to keep window on top
132
+ * @example
133
+ * msgapi.setAlwaysOnTop(true);
134
+ */
135
+ setAlwaysOnTop(enabled: boolean): void;
136
+ /**
137
+ * Set window title
138
+ * @param title - New window title
139
+ * @example
140
+ * msgapi.setTitle("My Application");
141
+ */
142
+ setTitle(title: string): void;
143
+ /**
144
+ * Close the window
145
+ * @param result - Optional result to return to parent process
146
+ * @example
147
+ * // Close with default dismissed result
148
+ * msgapi.close();
149
+ *
150
+ * // Close with custom result
151
+ * msgapi.close({button: 'OK', value: 'user data'});
152
+ */
153
+ close(result?: Partial<MsgResult>): void;
154
+ /**
155
+ * Send result and close window (legacy compatibility)
156
+ * @param result - Result to return to parent process
157
+ * @example
158
+ * msgapi.sendResult({button: 'Submit', value: 'form data'});
159
+ */
160
+ sendResult(result: Partial<MsgResult>): void;
161
+ /**
162
+ * Save data to persistent storage
163
+ * Data is stored with 'msgapi_' prefix in localStorage
164
+ * @param key - Storage key
165
+ * @param value - Value to store (will be JSON.stringify'd)
166
+ * @returns true on success, false on failure
167
+ * @example
168
+ * msgapi.saveData('userPrefs', {theme: 'dark', fontSize: 14});
169
+ */
170
+ saveData(key: string, value: any): boolean;
171
+ /**
172
+ * Load data from persistent storage
173
+ * @param key - Storage key
174
+ * @param defaultValue - Default value if key not found
175
+ * @returns Stored value or defaultValue
176
+ * @example
177
+ * const prefs = msgapi.loadData('userPrefs', {theme: 'light'});
178
+ */
179
+ loadData<T = any>(key: string, defaultValue?: T): T;
180
+ /**
181
+ * Remove data from persistent storage
182
+ * @param key - Storage key to remove
183
+ * @returns true on success, false on failure
184
+ * @example
185
+ * msgapi.removeData('tempData');
186
+ */
187
+ removeData(key: string): boolean;
188
+ /**
189
+ * Clear all msgapi data from persistent storage
190
+ * Only removes items with 'msgapi_' prefix
191
+ * @returns true on success, false on failure
192
+ * @example
193
+ * msgapi.clearData();
194
+ */
195
+ clearData(): boolean;
196
+ /**
197
+ * File system operations namespace
198
+ */
199
+ fs?: {
200
+ /**
201
+ * Select a file using native file picker
202
+ * @param options - File dialog options
203
+ * @returns Selected file with content, or null if cancelled
204
+ * @example
205
+ * const file = await msgapi.fs.selectFile({
206
+ * title: 'Open File',
207
+ * filters: [{name: 'Text', extensions: ['txt', 'md']}]
208
+ * });
209
+ * if (file) {
210
+ * console.log(file.content);
211
+ * }
212
+ */
213
+ selectFile(options?: FileDialogOptions): Promise<SelectedFile | null>;
214
+ /**
215
+ * Select multiple files using native file picker
216
+ * @param options - File dialog options
217
+ * @returns Array of selected files with content
218
+ * @example
219
+ * const files = await msgapi.fs.selectFiles({
220
+ * title: 'Open Files'
221
+ * });
222
+ */
223
+ selectFiles(options?: FileDialogOptions): Promise<SelectedFile[]>;
224
+ /**
225
+ * Save file using native save dialog
226
+ * @param content - File content to save
227
+ * @param defaultFilename - Default filename
228
+ * @param options - Additional dialog options
229
+ * @returns Path where file was saved, or null if cancelled
230
+ * @example
231
+ * const path = await msgapi.fs.saveFileAs('Hello World', 'greeting.txt');
232
+ */
233
+ saveFileAs(content: string, defaultFilename?: string, options?: FileDialogOptions): Promise<string | null>;
234
+ /**
235
+ * Select a directory using native folder picker
236
+ * @param options - Dialog options
237
+ * @returns Selected directory path, or null if cancelled
238
+ * @example
239
+ * const dir = await msgapi.fs.selectFolder({
240
+ * title: 'Select Output Folder'
241
+ * });
242
+ */
243
+ selectFolder(options?: FileDialogOptions): Promise<string | null>;
244
+ /**
245
+ * Read file contents
246
+ * Note: Requires allowFs: true flag when launching msgview/msger
247
+ * @param path - File path to read
248
+ * @returns File content as string
249
+ * @example
250
+ * const content = await msgapi.fs.read('/path/to/file.txt');
251
+ */
252
+ read(path: string): Promise<string>;
253
+ /**
254
+ * Write file contents
255
+ * Note: Requires allowFs: true flag when launching msgview/msger
256
+ * @param path - File path to write
257
+ * @param content - Content to write
258
+ * @example
259
+ * await msgapi.fs.write('/path/to/file.txt', 'Hello World');
260
+ */
261
+ write(path: string, content: string): Promise<void>;
262
+ /**
263
+ * List directory contents
264
+ * Note: Requires allowFs: true flag when launching msgview/msger
265
+ * @param path - Directory path to list
266
+ * @returns Array of file information
267
+ * @example
268
+ * const files = await msgapi.fs.list('/path/to/dir');
269
+ */
270
+ list(path: string): Promise<FileInfo[]>;
271
+ /**
272
+ * Check if file or directory exists
273
+ * Note: Requires allowFs: true flag when launching msgview/msger
274
+ * @param path - Path to check
275
+ * @returns true if exists
276
+ * @example
277
+ * const exists = await msgapi.fs.exists('/path/to/file.txt');
278
+ */
279
+ exists(path: string): Promise<boolean>;
280
+ /**
281
+ * Delete file or directory
282
+ * Note: Requires allowFs: true flag when launching msgview/msger
283
+ * @param path - Path to delete
284
+ * @example
285
+ * await msgapi.fs.delete('/path/to/file.txt');
286
+ */
287
+ delete(path: string): Promise<void>;
288
+ };
289
+ }
290
+ /**
291
+ * Helper to check if code is running in msgview/msger
292
+ * @returns true if running in msgapi environment
293
+ * @example
294
+ * if (isMsgAPI()) {
295
+ * msgapi.setTitle('Running in msgview/msger!');
296
+ * } else {
297
+ * console.log('Running in browser');
298
+ * }
299
+ */
300
+ export declare function isMsgAPI(): boolean;
301
+ /**
302
+ * Get msgapi API with fallback for browser compatibility
303
+ * @returns msgapi API if available, or stub implementation for browser
304
+ * @example
305
+ * const api = getMsgAPI();
306
+ * api.saveData('key', 'value'); // Works in both msgview/msger and browser
307
+ */
308
+ export declare function getMsgAPI(): MsgAPI;
309
+ /**
310
+ * Declare global window.msgapi
311
+ */
312
+ declare global {
313
+ interface Window {
314
+ msgapi?: MsgAPI;
315
+ }
316
+ }
317
+ declare const _default: {
318
+ isMsgAPI: typeof isMsgAPI;
319
+ getMsgAPI: typeof getMsgAPI;
320
+ };
321
+ export default _default;
322
+ //# sourceMappingURL=msgapidefs.d.ts.map
package/msgapidefs.js ADDED
@@ -0,0 +1,110 @@
1
+ /**
2
+ * TypeScript definitions for the msgapi JavaScript API
3
+ *
4
+ * This module provides type-safe access to msgapi's window control,
5
+ * data persistence, and file system features (used by msgview and msger).
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import type { MsgAPI } from '@bobfrankston/msgapidefs';
10
+ *
11
+ * declare global {
12
+ * interface Window {
13
+ * msgapi?: MsgAPI;
14
+ * }
15
+ * }
16
+ *
17
+ * // Check if running in msgview/msger
18
+ * if (window.msgapi) {
19
+ * window.msgapi.setTitle('My App');
20
+ * }
21
+ * ```
22
+ */
23
+ /**
24
+ * Helper to check if code is running in msgview/msger
25
+ * @returns true if running in msgapi environment
26
+ * @example
27
+ * if (isMsgAPI()) {
28
+ * msgapi.setTitle('Running in msgview/msger!');
29
+ * } else {
30
+ * console.log('Running in browser');
31
+ * }
32
+ */
33
+ export function isMsgAPI() {
34
+ return typeof window !== 'undefined' && typeof window.msgapi !== 'undefined';
35
+ }
36
+ /**
37
+ * Get msgapi API with fallback for browser compatibility
38
+ * @returns msgapi API if available, or stub implementation for browser
39
+ * @example
40
+ * const api = getMsgAPI();
41
+ * api.saveData('key', 'value'); // Works in both msgview/msger and browser
42
+ */
43
+ export function getMsgAPI() {
44
+ if (isMsgAPI()) {
45
+ return window.msgapi;
46
+ }
47
+ // Return browser-compatible stub
48
+ return {
49
+ // Window control - no-op in browser
50
+ toggleFullscreen: () => { },
51
+ setFullscreen: () => { },
52
+ minimize: () => { },
53
+ maximize: () => { },
54
+ setSize: () => { },
55
+ setPosition: () => { },
56
+ setAlwaysOnTop: () => { },
57
+ setTitle: (title) => { document.title = title; },
58
+ close: () => { window.close(); },
59
+ sendResult: () => { window.close(); },
60
+ // Data persistence - use localStorage in browser
61
+ saveData: (key, value) => {
62
+ try {
63
+ localStorage.setItem('msgapi_' + key, JSON.stringify(value));
64
+ return true;
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ },
70
+ loadData: (key, defaultValue) => {
71
+ try {
72
+ const item = localStorage.getItem('msgapi_' + key);
73
+ return item ? JSON.parse(item) : defaultValue;
74
+ }
75
+ catch {
76
+ return defaultValue;
77
+ }
78
+ },
79
+ removeData: (key) => {
80
+ try {
81
+ localStorage.removeItem('msgapi_' + key);
82
+ return true;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ },
88
+ clearData: () => {
89
+ try {
90
+ const keys = Object.keys(localStorage);
91
+ for (const key of keys) {
92
+ if (key.startsWith('msgapi_')) {
93
+ localStorage.removeItem(key);
94
+ }
95
+ }
96
+ return true;
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ },
102
+ // File system - not available in browser
103
+ fs: undefined
104
+ };
105
+ }
106
+ export default {
107
+ isMsgAPI,
108
+ getMsgAPI
109
+ };
110
+ //# sourceMappingURL=msgapidefs.js.map