@wavecraft/core 0.7.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,67 @@
1
+ # @wavecraft/core
2
+
3
+ Core SDK for Wavecraft audio plugins — IPC bridge, hooks, and utilities.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @wavecraft/core
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```tsx
14
+ import { useParameter, useMeterFrame, logger } from '@wavecraft/core';
15
+
16
+ function MyComponent() {
17
+ const { param, setValue } = useParameter('gain');
18
+ const meterFrame = useMeterFrame();
19
+
20
+ return (
21
+ <input
22
+ type="range"
23
+ value={param?.value ?? 0}
24
+ onChange={(e) => setValue(parseFloat(e.target.value))}
25
+ />
26
+ );
27
+ }
28
+ ```
29
+
30
+ ## API Reference
31
+
32
+ ### Hooks
33
+
34
+ | Hook | Description |
35
+ |------|-------------|
36
+ | `useParameter(id)` | Get/set a single parameter |
37
+ | `useAllParameters()` | Get all plugin parameters |
38
+ | `useParameterGroups()` | Get parameters organized by group |
39
+ | `useMeterFrame()` | Get current audio meter levels |
40
+ | `useConnectionStatus()` | Monitor IPC connection status |
41
+ | `useRequestResize()` | Request plugin window resize |
42
+ | `useLatencyMonitor()` | Monitor IPC roundtrip latency |
43
+
44
+ ### Utilities
45
+
46
+ ```typescript
47
+ import { linearToDb, dbToLinear } from '@wavecraft/core/meters';
48
+
49
+ linearToDb(0.5); // → -6.02 dB
50
+ dbToLinear(-6); // → 0.501
51
+ ```
52
+
53
+ ### Advanced: IPC Bridge
54
+
55
+ For custom implementations:
56
+
57
+ ```typescript
58
+ import { IpcBridge, ParameterClient } from '@wavecraft/core';
59
+ ```
60
+
61
+ ## Requirements
62
+
63
+ - React 18+
64
+
65
+ ## License
66
+
67
+ MIT
@@ -0,0 +1,573 @@
1
+ export declare interface ConnectionStatus {
2
+ /** Whether transport is connected and ready */
3
+ connected: boolean;
4
+ /** Type of transport being used */
5
+ transport: TransportType;
6
+ }
7
+
8
+ /**
9
+ * Convert decibels to linear amplitude
10
+ * @param db Decibels
11
+ */
12
+ export declare function dbToLinear(db: number): number;
13
+
14
+ export declare const ERROR_INTERNAL = -32603;
15
+
16
+ export declare const ERROR_INVALID_PARAMS = -32602;
17
+
18
+ export declare const ERROR_INVALID_REQUEST = -32600;
19
+
20
+ export declare const ERROR_METHOD_NOT_FOUND = -32601;
21
+
22
+ export declare const ERROR_PARAM_NOT_FOUND = -32000;
23
+
24
+ export declare const ERROR_PARAM_OUT_OF_RANGE = -32001;
25
+
26
+ export declare const ERROR_PARSE = -32700;
27
+
28
+ /**
29
+ * IpcBridge - Low-level IPC communication layer
30
+ *
31
+ * Provides a Promise-based API for sending requests and receiving responses
32
+ * using pluggable transport implementations (NativeTransport, WebSocketTransport).
33
+ */
34
+ declare type EventCallback<T> = (data: T) => void;
35
+
36
+ export declare interface GetAllParametersResult {
37
+ parameters: ParameterInfo[];
38
+ }
39
+
40
+ /**
41
+ * Get the latest meter frame from the audio engine
42
+ */
43
+ export declare function getMeterFrame(): Promise<MeterFrame | null>;
44
+
45
+ /**
46
+ * Result from getMeterFrame method
47
+ */
48
+ export declare interface GetMeterFrameResult {
49
+ frame: MeterFrame | null;
50
+ }
51
+
52
+ export declare interface GetParameterParams {
53
+ id: string;
54
+ }
55
+
56
+ export declare interface GetParameterResult {
57
+ id: string;
58
+ value: number;
59
+ }
60
+
61
+ export declare class IpcBridge {
62
+ private static instance;
63
+ private nextId;
64
+ private readonly eventListeners;
65
+ private transport;
66
+ private isInitialized;
67
+ private lastDisconnectWarning;
68
+ private readonly DISCONNECT_WARNING_INTERVAL_MS;
69
+ private constructor();
70
+ /**
71
+ * Initialize the IPC bridge (lazy)
72
+ */
73
+ private initialize;
74
+ /**
75
+ * Get singleton instance
76
+ */
77
+ static getInstance(): IpcBridge;
78
+ /**
79
+ * Check if the bridge is connected
80
+ */
81
+ isConnected(): boolean;
82
+ /**
83
+ * Invoke a method and wait for response
84
+ */
85
+ invoke<TResult>(method: string, params?: unknown): Promise<TResult>;
86
+ /**
87
+ * Subscribe to notification events
88
+ */
89
+ on<T>(event: string, callback: EventCallback<T>): () => void;
90
+ /**
91
+ * Handle notification and dispatch to listeners
92
+ */
93
+ private handleNotification;
94
+ }
95
+
96
+ export declare interface IpcError {
97
+ code: number;
98
+ message: string;
99
+ data?: unknown;
100
+ }
101
+
102
+ export declare interface IpcNotification {
103
+ jsonrpc: '2.0';
104
+ method: string;
105
+ params?: unknown;
106
+ }
107
+
108
+ export declare interface IpcRequest {
109
+ jsonrpc: '2.0';
110
+ id: RequestId;
111
+ method: string;
112
+ params?: unknown;
113
+ }
114
+
115
+ export declare interface IpcResponse {
116
+ jsonrpc: '2.0';
117
+ id: RequestId;
118
+ result?: unknown;
119
+ error?: IpcError;
120
+ }
121
+
122
+ /**
123
+ * Check if running in a browser environment (development)
124
+ * @returns true if IPC primitives are NOT available
125
+ */
126
+ export declare function isBrowserEnvironment(): boolean;
127
+
128
+ /**
129
+ * Environment Detection
130
+ *
131
+ * Determines if the code is running in WKWebView (production)
132
+ * or a browser (development).
133
+ */
134
+ /**
135
+ * Check if running in a WKWebView environment (production)
136
+ * @returns true if globalThis.wavecraft IPC primitives are available
137
+ */
138
+ export declare function isWebViewEnvironment(): boolean;
139
+
140
+ /**
141
+ * Convert linear amplitude to decibels
142
+ * @param linear Linear amplitude (0.0 to 1.0+)
143
+ * @param floor Minimum dB value to return (default: -60)
144
+ */
145
+ export declare function linearToDb(linear: number, floor?: number): number;
146
+
147
+ export declare interface LogContext {
148
+ [key: string]: unknown;
149
+ }
150
+
151
+ /**
152
+ * Logger class providing structured logging with severity levels.
153
+ *
154
+ * Example usage:
155
+ * ```typescript
156
+ * const logger = new Logger({ minLevel: LogLevel.INFO });
157
+ * logger.info('Parameter updated', { id: 'gain', value: 0.5 });
158
+ * logger.error('IPC failed', { method: 'getParameter', error });
159
+ * ```
160
+ */
161
+ export declare class Logger {
162
+ private minLevel;
163
+ constructor(options?: {
164
+ minLevel?: LogLevel;
165
+ });
166
+ /**
167
+ * Set the minimum log level at runtime.
168
+ */
169
+ setMinLevel(level: LogLevel): void;
170
+ /**
171
+ * Log debug message (verbose tracing).
172
+ */
173
+ debug(message: string, context?: LogContext): void;
174
+ /**
175
+ * Log informational message.
176
+ */
177
+ info(message: string, context?: LogContext): void;
178
+ /**
179
+ * Log warning message.
180
+ */
181
+ warn(message: string, context?: LogContext): void;
182
+ /**
183
+ * Log error message.
184
+ */
185
+ error(message: string, context?: LogContext): void;
186
+ }
187
+
188
+ /**
189
+ * Global logger instance for the UI.
190
+ * Configure once at app startup, use throughout the codebase.
191
+ */
192
+ export declare const logger: Logger;
193
+
194
+ /**
195
+ * Logger - Structured logging abstraction for the UI.
196
+ *
197
+ * Wraps browser console API with severity levels and structured context.
198
+ * In production builds, logs can be filtered by level at runtime.
199
+ */
200
+ export declare enum LogLevel {
201
+ DEBUG = 0,
202
+ INFO = 1,
203
+ WARN = 2,
204
+ ERROR = 3
205
+ }
206
+
207
+ /**
208
+ * Meter frame data (all values in linear scale, not dB)
209
+ */
210
+ export declare interface MeterFrame {
211
+ peak_l: number;
212
+ peak_r: number;
213
+ rms_l: number;
214
+ rms_r: number;
215
+ timestamp: number;
216
+ }
217
+
218
+ export declare const METHOD_GET_ALL_PARAMETERS = "getAllParameters";
219
+
220
+ export declare const METHOD_GET_PARAMETER = "getParameter";
221
+
222
+ export declare const METHOD_SET_PARAMETER = "setParameter";
223
+
224
+ /**
225
+ * Native WKWebView transport implementation
226
+ *
227
+ * Uses the __WAVECRAFT_IPC__ primitives injected by the Rust engine.
228
+ */
229
+ export declare class NativeTransport implements Transport {
230
+ private readonly pendingRequests;
231
+ private readonly notificationCallbacks;
232
+ private readonly primitives;
233
+ constructor();
234
+ /**
235
+ * Send a JSON-RPC request and wait for response
236
+ */
237
+ send(request: string): Promise<string>;
238
+ /**
239
+ * Register a callback for incoming notifications
240
+ */
241
+ onNotification(callback: NotificationCallback): () => void;
242
+ /**
243
+ * Check if transport is connected (native is always connected)
244
+ */
245
+ isConnected(): boolean;
246
+ /**
247
+ * Clean up resources
248
+ */
249
+ dispose(): void;
250
+ /**
251
+ * Handle incoming message (response or notification)
252
+ */
253
+ private handleIncomingMessage;
254
+ /**
255
+ * Handle JSON-RPC response
256
+ */
257
+ private handleResponse;
258
+ /**
259
+ * Handle notification and dispatch to listeners
260
+ */
261
+ private handleNotification;
262
+ }
263
+
264
+ export declare const NOTIFICATION_PARAMETER_CHANGED = "parameterChanged";
265
+
266
+ /**
267
+ * Transport interface for IPC communication
268
+ *
269
+ * Provides an abstraction layer for different transport mechanisms
270
+ * (native WKWebView, WebSocket) with consistent request/notification handling.
271
+ */
272
+ /**
273
+ * Callback for handling incoming notifications from the engine
274
+ */
275
+ export declare type NotificationCallback = (notification: string) => void;
276
+
277
+ declare type ParameterChangeCallback = (id: string, value: number) => void;
278
+
279
+ export declare interface ParameterChangedNotification {
280
+ id: string;
281
+ value: number;
282
+ }
283
+
284
+ export declare class ParameterClient {
285
+ private static instance;
286
+ private bridge;
287
+ private constructor();
288
+ /**
289
+ * Get singleton instance
290
+ */
291
+ static getInstance(): ParameterClient;
292
+ /**
293
+ * Get a single parameter's current value and metadata
294
+ */
295
+ getParameter(id: string): Promise<GetParameterResult>;
296
+ /**
297
+ * Set a parameter's value
298
+ * @param id Parameter ID
299
+ * @param value Normalized value [0.0, 1.0]
300
+ */
301
+ setParameter(id: string, value: number): Promise<void>;
302
+ /**
303
+ * Get all parameters with their current values and metadata
304
+ */
305
+ getAllParameters(): Promise<ParameterInfo[]>;
306
+ /**
307
+ * Test connectivity with Rust backend
308
+ * @returns Roundtrip time in milliseconds
309
+ */
310
+ ping(): Promise<number>;
311
+ /**
312
+ * Subscribe to parameter change notifications
313
+ * @returns Unsubscribe function
314
+ */
315
+ onParameterChanged(callback: ParameterChangeCallback): () => void;
316
+ }
317
+
318
+ export declare interface ParameterGroup {
319
+ name: string;
320
+ parameters: ParameterInfo[];
321
+ }
322
+
323
+ export declare interface ParameterInfo {
324
+ id: string;
325
+ name: string;
326
+ type: ParameterType;
327
+ value: number;
328
+ default: number;
329
+ unit?: string;
330
+ group?: string;
331
+ }
332
+
333
+ export declare type ParameterType = 'float' | 'bool' | 'enum';
334
+
335
+ /**
336
+ * IPC Types - TypeScript definitions matching Rust protocol
337
+ *
338
+ * These types must stay in sync with engine/crates/protocol/src/ipc.rs
339
+ */
340
+ export declare type RequestId = string | number;
341
+
342
+ /**
343
+ * Request resize of the editor window
344
+ *
345
+ * @param width - Desired width in logical pixels
346
+ * @param height - Desired height in logical pixels
347
+ * @returns Promise that resolves to true if accepted, false if rejected
348
+ *
349
+ * @example
350
+ * ```ts
351
+ * const accepted = await requestResize(1024, 768);
352
+ * if (accepted) {
353
+ * console.log('Resize accepted by host');
354
+ * } else {
355
+ * console.warn('Resize rejected by host');
356
+ * }
357
+ * ```
358
+ */
359
+ export declare function requestResize(width: number, height: number): Promise<boolean>;
360
+
361
+ /**
362
+ * Window resize utilities
363
+ *
364
+ * Provides functions for requesting window resize from the host DAW.
365
+ */
366
+ export declare interface RequestResizeParams {
367
+ width: number;
368
+ height: number;
369
+ }
370
+
371
+ export declare interface RequestResizeResult {
372
+ accepted: boolean;
373
+ }
374
+
375
+ export declare interface SetParameterParams {
376
+ id: string;
377
+ value: number;
378
+ }
379
+
380
+ export declare type SetParameterResult = Record<string, never>;
381
+
382
+ /**
383
+ * Transport abstraction for IPC communication
384
+ *
385
+ * Implementations handle the low-level details of sending requests,
386
+ * receiving responses, and dispatching notifications.
387
+ */
388
+ export declare interface Transport {
389
+ /**
390
+ * Send a JSON-RPC request and wait for the response
391
+ *
392
+ * @param request - JSON-RPC request string
393
+ * @returns Promise resolving to JSON-RPC response string
394
+ * @throws Error if transport is not connected or request fails
395
+ */
396
+ send(request: string): Promise<string>;
397
+ /**
398
+ * Register a callback for incoming notifications from the engine
399
+ *
400
+ * @param callback - Function called when a notification arrives
401
+ * @returns Cleanup function to remove the callback
402
+ */
403
+ onNotification(callback: NotificationCallback): () => void;
404
+ /**
405
+ * Check if the transport is currently connected
406
+ *
407
+ * @returns true if transport can send/receive messages
408
+ */
409
+ isConnected(): boolean;
410
+ /**
411
+ * Clean up resources (close connections, remove listeners)
412
+ *
413
+ * Should be called when the transport is no longer needed.
414
+ */
415
+ dispose(): void;
416
+ }
417
+
418
+ /**
419
+ * useConnectionStatus - Monitor transport connection status
420
+ *
421
+ * Provides real-time connection status updates for the IPC transport.
422
+ * Useful for showing connection indicators in the UI.
423
+ */
424
+ export declare type TransportType = 'native' | 'websocket' | 'none';
425
+
426
+ export declare function useAllParameters(): UseAllParametersResult;
427
+
428
+ export declare interface UseAllParametersResult {
429
+ params: ParameterInfo[];
430
+ isLoading: boolean;
431
+ error: Error | null;
432
+ reload: () => Promise<void>;
433
+ }
434
+
435
+ /**
436
+ * Hook to monitor IPC connection status
437
+ *
438
+ * Polls the transport every second to detect connection changes.
439
+ * Native transport is always connected, WebSocket may reconnect.
440
+ *
441
+ * @returns Connection status object
442
+ */
443
+ export declare function useConnectionStatus(): ConnectionStatus;
444
+
445
+ export declare function useLatencyMonitor(intervalMs?: number): UseLatencyMonitorResult;
446
+
447
+ export declare interface UseLatencyMonitorResult {
448
+ latency: number | null;
449
+ avg: number;
450
+ max: number;
451
+ count: number;
452
+ }
453
+
454
+ export declare function useParameter(id: string): UseParameterResult;
455
+
456
+ /**
457
+ * Organize parameters into groups based on their group metadata.
458
+ *
459
+ * @param parameters - Array of all parameters
460
+ * @returns Array of parameter groups, each containing parameters for that group
461
+ *
462
+ * @example
463
+ * ```tsx
464
+ * const { parameters } = useAllParameters();
465
+ * const groups = useParameterGroups(parameters);
466
+ *
467
+ * return (
468
+ * <>
469
+ * {groups.map(group => (
470
+ * <ParameterGroup key={group.name} group={group} />
471
+ * ))}
472
+ * </>
473
+ * );
474
+ * ```
475
+ */
476
+ export declare function useParameterGroups(parameters: ParameterInfo[]): ParameterGroup[];
477
+
478
+ export declare interface UseParameterResult {
479
+ param: ParameterInfo | null;
480
+ setValue: (value: number) => Promise<void>;
481
+ isLoading: boolean;
482
+ error: Error | null;
483
+ }
484
+
485
+ /**
486
+ * React hook for requesting window resize
487
+ *
488
+ * @returns Function to request resize
489
+ *
490
+ * @example
491
+ * ```tsx
492
+ * function MyComponent() {
493
+ * const resize = useRequestResize();
494
+ *
495
+ * const handleExpand = async () => {
496
+ * const accepted = await resize(1200, 900);
497
+ * if (!accepted) {
498
+ * alert('Host rejected resize request');
499
+ * }
500
+ * };
501
+ *
502
+ * return <button onClick={handleExpand}>Expand</button>;
503
+ * }
504
+ * ```
505
+ */
506
+ export declare function useRequestResize(): (width: number, height: number) => Promise<boolean>;
507
+
508
+ /**
509
+ * WebSocket transport implementation with automatic reconnection
510
+ *
511
+ * Connects to the standalone dev server for browser-based UI development.
512
+ */
513
+ export declare class WebSocketTransport implements Transport {
514
+ private readonly url;
515
+ private readonly reconnectDelayMs;
516
+ private readonly maxReconnectAttempts;
517
+ private ws;
518
+ private isConnecting;
519
+ private reconnectAttempts;
520
+ private reconnectTimeoutId;
521
+ private isDisposed;
522
+ private maxAttemptsReached;
523
+ private readonly pendingRequests;
524
+ private readonly notificationCallbacks;
525
+ constructor(options: WebSocketTransportOptions);
526
+ /**
527
+ * Send a JSON-RPC request and wait for response
528
+ */
529
+ send(request: string): Promise<string>;
530
+ /**
531
+ * Register a callback for incoming notifications
532
+ */
533
+ onNotification(callback: NotificationCallback): () => void;
534
+ /**
535
+ * Check if transport is connected
536
+ */
537
+ isConnected(): boolean;
538
+ /**
539
+ * Clean up resources and close connection
540
+ */
541
+ dispose(): void;
542
+ /**
543
+ * Attempt to connect to WebSocket server
544
+ */
545
+ private connect;
546
+ /**
547
+ * Schedule reconnection attempt with exponential backoff
548
+ */
549
+ private scheduleReconnect;
550
+ /**
551
+ * Handle incoming message (response or notification)
552
+ */
553
+ private handleIncomingMessage;
554
+ /**
555
+ * Handle JSON-RPC response
556
+ */
557
+ private handleResponse;
558
+ /**
559
+ * Handle notification and dispatch to listeners
560
+ */
561
+ private handleNotification;
562
+ }
563
+
564
+ declare interface WebSocketTransportOptions {
565
+ /** WebSocket server URL (e.g., ws://127.0.0.1:9000) */
566
+ url: string;
567
+ /** Reconnection delay in milliseconds (default: 1000) */
568
+ reconnectDelayMs?: number;
569
+ /** Maximum reconnection attempts (default: 5, use Infinity for unlimited) */
570
+ maxReconnectAttempts?: number;
571
+ }
572
+
573
+ export { }