@aspectly/transports 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.
Files changed (55) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +368 -0
  3. package/dist/BaseTransport-CxzIr1Ds.d.mts +80 -0
  4. package/dist/BaseTransport-CxzIr1Ds.d.ts +80 -0
  5. package/dist/cefsharp.d.mts +37 -0
  6. package/dist/cefsharp.d.ts +37 -0
  7. package/dist/cefsharp.js +65 -0
  8. package/dist/cefsharp.js.map +1 -0
  9. package/dist/cefsharp.mjs +62 -0
  10. package/dist/cefsharp.mjs.map +1 -0
  11. package/dist/iframe.d.mts +35 -0
  12. package/dist/iframe.d.ts +35 -0
  13. package/dist/iframe.js +75 -0
  14. package/dist/iframe.js.map +1 -0
  15. package/dist/iframe.mjs +72 -0
  16. package/dist/iframe.mjs.map +1 -0
  17. package/dist/index.d.mts +85 -0
  18. package/dist/index.d.ts +85 -0
  19. package/dist/index.js +374 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/index.mjs +358 -0
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/react-native.d.mts +36 -0
  24. package/dist/react-native.d.ts +36 -0
  25. package/dist/react-native.js +65 -0
  26. package/dist/react-native.js.map +1 -0
  27. package/dist/react-native.mjs +62 -0
  28. package/dist/react-native.mjs.map +1 -0
  29. package/dist/window.d.mts +36 -0
  30. package/dist/window.d.ts +36 -0
  31. package/dist/window.js +79 -0
  32. package/dist/window.js.map +1 -0
  33. package/dist/window.mjs +76 -0
  34. package/dist/window.mjs.map +1 -0
  35. package/package.json +97 -0
  36. package/src/BaseTransport.test.ts +60 -0
  37. package/src/BaseTransport.ts +27 -0
  38. package/src/TransportRegistry.test.ts +345 -0
  39. package/src/TransportRegistry.ts +120 -0
  40. package/src/cefsharp.ts +3 -0
  41. package/src/iframe.ts +3 -0
  42. package/src/index.ts +26 -0
  43. package/src/react-native.ts +3 -0
  44. package/src/transports/CefSharpTransport.test.ts +187 -0
  45. package/src/transports/CefSharpTransport.ts +73 -0
  46. package/src/transports/IframeTransport.test.ts +212 -0
  47. package/src/transports/IframeTransport.ts +79 -0
  48. package/src/transports/NullTransport.test.ts +64 -0
  49. package/src/transports/NullTransport.ts +27 -0
  50. package/src/transports/PostMessageTransport.ts +50 -0
  51. package/src/transports/ReactNativeTransport.test.ts +196 -0
  52. package/src/transports/ReactNativeTransport.ts +73 -0
  53. package/src/transports/WindowTransport.ts +84 -0
  54. package/src/types.ts +69 -0
  55. package/src/window.ts +3 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Zhan Isaakian
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,368 @@
1
+ # @aspectly/transports
2
+
3
+ Transport layer for cross-platform communication between WebViews, iframes, and web applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # npm
9
+ npm install @aspectly/transports
10
+
11
+ # pnpm
12
+ pnpm add @aspectly/transports
13
+
14
+ # yarn
15
+ yarn add @aspectly/transports
16
+ ```
17
+
18
+ ## Overview
19
+
20
+ `@aspectly/transports` provides a flexible abstraction layer for platform detection and message passing across different execution contexts. It automatically detects the current environment (CefSharp, React Native WebView, iframe, or browser) and provides a unified API for bidirectional communication.
21
+
22
+ ### Built-in Transports
23
+
24
+ | Transport | Detection | Priority | Use Case |
25
+ |-----------|-----------|----------|----------|
26
+ | **CefSharpTransport** | `window.CefSharp.PostMessage` | 100 | Desktop apps with CefSharp (Chromium Embedded Framework for .NET) |
27
+ | **ReactNativeTransport** | `window.ReactNativeWebView.postMessage` | 90 | React Native WebView |
28
+ | **IframeTransport** | `window.parent !== window` | 80 | Web content inside iframes |
29
+ | **NullTransport** | Always available | - | Fallback for SSR/testing (no-op) |
30
+
31
+ ### Auto-Detection
32
+
33
+ The `TransportRegistry` automatically selects the appropriate transport based on priority order. Higher priority transports are checked first, ensuring the most specific transport is used.
34
+
35
+ ## Quick Start
36
+
37
+ ### Auto-Detection (Recommended)
38
+
39
+ ```typescript
40
+ import { detectTransport } from '@aspectly/transports';
41
+
42
+ // Automatically detect the current environment
43
+ const transport = detectTransport();
44
+ console.log(`Using transport: ${transport.name}`); // 'cefsharp', 'react-native', 'iframe', or 'null'
45
+
46
+ // Send a message
47
+ transport.send(JSON.stringify({ type: 'hello', data: 'world' }));
48
+
49
+ // Subscribe to incoming messages
50
+ const unsubscribe = transport.subscribe((message) => {
51
+ const data = JSON.parse(message);
52
+ console.log('Received:', data);
53
+ });
54
+
55
+ // Cleanup when done
56
+ unsubscribe();
57
+ ```
58
+
59
+ ### Direct Transport Usage
60
+
61
+ ```typescript
62
+ import { CefSharpTransport } from '@aspectly/transports';
63
+
64
+ const transport = new CefSharpTransport();
65
+
66
+ if (transport.isAvailable()) {
67
+ transport.send(JSON.stringify({ method: 'getData' }));
68
+ }
69
+ ```
70
+
71
+ ### Custom Transport Registration
72
+
73
+ ```typescript
74
+ import { registerTransport, detectTransport } from '@aspectly/transports';
75
+
76
+ // Register a custom transport with high priority
77
+ registerTransport({
78
+ name: 'electron',
79
+ priority: 150, // Higher than CefSharp (100)
80
+ detect: () => {
81
+ return typeof window !== 'undefined' &&
82
+ window.electron?.send !== undefined;
83
+ },
84
+ createTransport: () => new ElectronTransport(),
85
+ });
86
+
87
+ // Now auto-detection will check your custom transport first
88
+ const transport = detectTransport();
89
+ ```
90
+
91
+ ## API Reference
92
+
93
+ ### Transport Interface
94
+
95
+ The core interface implemented by all transports:
96
+
97
+ ```typescript
98
+ interface Transport {
99
+ readonly name: string;
100
+ isAvailable(): boolean;
101
+ send(message: string): void;
102
+ subscribe(listener: TransportListener): TransportUnsubscribe;
103
+ }
104
+ ```
105
+
106
+ **Properties:**
107
+ - `name` - Unique identifier for the transport (e.g., 'cefsharp', 'react-native')
108
+
109
+ **Methods:**
110
+ - `isAvailable()` - Check if the transport is available in the current environment
111
+ - `send(message: string)` - Send a message to the parent/host context
112
+ - `subscribe(listener)` - Subscribe to incoming messages, returns cleanup function
113
+
114
+ ### Types
115
+
116
+ ```typescript
117
+ // Message listener callback
118
+ type TransportListener = (message: string) => void;
119
+
120
+ // Cleanup function returned by subscribe
121
+ type TransportUnsubscribe = () => void;
122
+
123
+ // Factory function for creating transports
124
+ type TransportFactory = () => Transport;
125
+ ```
126
+
127
+ ### TransportDetector Interface
128
+
129
+ Used for registering custom transports:
130
+
131
+ ```typescript
132
+ interface TransportDetector {
133
+ readonly name: string;
134
+ readonly priority: number;
135
+ detect(): boolean;
136
+ createTransport(): Transport;
137
+ }
138
+ ```
139
+
140
+ **Properties:**
141
+ - `name` - Transport identifier
142
+ - `priority` - Detection priority (higher values checked first)
143
+
144
+ **Methods:**
145
+ - `detect()` - Return `true` if this transport is available
146
+ - `createTransport()` - Create and return a transport instance
147
+
148
+ ### BaseTransport Class
149
+
150
+ Abstract base class providing common functionality:
151
+
152
+ ```typescript
153
+ abstract class BaseTransport implements Transport {
154
+ abstract readonly name: string;
155
+ abstract isAvailable(): boolean;
156
+ abstract send(message: string): void;
157
+ abstract subscribe(listener: TransportListener): TransportUnsubscribe;
158
+
159
+ protected hasWindow(): boolean;
160
+ protected getWindow(): Window | null;
161
+ }
162
+ ```
163
+
164
+ **Protected Helpers:**
165
+ - `hasWindow()` - Check if `window` is defined (SSR-safe)
166
+ - `getWindow()` - Safely get the `window` object or `null`
167
+
168
+ ### TransportRegistry
169
+
170
+ Global registry for managing transport detectors:
171
+
172
+ ```typescript
173
+ class TransportRegistry {
174
+ register(detector: TransportDetector): void;
175
+ unregister(name: string): void;
176
+ getDetectors(): readonly TransportDetector[];
177
+ detect(forceRedetect?: boolean): Transport;
178
+ clearCache(): void;
179
+ reset(): void;
180
+ }
181
+ ```
182
+
183
+ **Methods:**
184
+ - `register(detector)` - Register a custom transport detector
185
+ - `unregister(name)` - Remove a detector by name
186
+ - `getDetectors()` - Get all registered detectors
187
+ - `detect(forceRedetect?)` - Detect and return the appropriate transport (cached)
188
+ - `clearCache()` - Clear the cached transport
189
+ - `reset()` - Reset to default state (built-in detectors only)
190
+
191
+ ### Convenience Functions
192
+
193
+ ```typescript
194
+ // Detect the current transport
195
+ function detectTransport(forceRedetect?: boolean): Transport;
196
+
197
+ // Register a custom detector
198
+ function registerTransport(detector: TransportDetector): void;
199
+ ```
200
+
201
+ ## Built-in Transports
202
+
203
+ ### CefSharpTransport
204
+
205
+ For desktop applications using [CefSharp](https://cefsharp.github.io/) (Chromium Embedded Framework for .NET).
206
+
207
+ **Detection:** Checks for `window.CefSharp.PostMessage`
208
+ **Priority:** 100 (highest)
209
+
210
+ ```typescript
211
+ import { CefSharpTransport } from '@aspectly/transports';
212
+
213
+ const transport = new CefSharpTransport();
214
+ transport.send(JSON.stringify({ action: 'openFile' }));
215
+
216
+ const unsubscribe = transport.subscribe((message) => {
217
+ console.log('From C#:', message);
218
+ });
219
+ ```
220
+
221
+ **Messaging:**
222
+ - Sends messages via `window.CefSharp.PostMessage(message)`
223
+ - Receives messages via `window.postMessage` events
224
+
225
+ ### ReactNativeTransport
226
+
227
+ For web content running inside [React Native WebView](https://github.com/react-native-webview/react-native-webview).
228
+
229
+ **Detection:** Checks for `window.ReactNativeWebView.postMessage`
230
+ **Priority:** 90
231
+
232
+ ```typescript
233
+ import { ReactNativeTransport } from '@aspectly/transports';
234
+
235
+ const transport = new ReactNativeTransport();
236
+ transport.send(JSON.stringify({ action: 'navigate' }));
237
+ ```
238
+
239
+ **Messaging:**
240
+ - Sends messages via `window.ReactNativeWebView.postMessage(message)`
241
+ - Messages are wrapped in quotes for iOS compatibility: `'${message}'`
242
+ - Receives messages via `window.postMessage` events
243
+
244
+ ### IframeTransport
245
+
246
+ For web content running inside an iframe.
247
+
248
+ **Detection:** Checks if `window.parent !== window`
249
+ **Priority:** 80
250
+
251
+ ```typescript
252
+ import { IframeTransport } from '@aspectly/transports';
253
+
254
+ // Default: sends to any origin ('*')
255
+ const transport = new IframeTransport();
256
+
257
+ // Specify target origin for security
258
+ const secureTransport = new IframeTransport('https://parent-domain.com');
259
+
260
+ transport.send(JSON.stringify({ type: 'ready' }));
261
+ ```
262
+
263
+ **Constructor:**
264
+ - `new IframeTransport(targetOrigin?: string)` - Default: `'*'`
265
+
266
+ **Messaging:**
267
+ - Sends messages via `window.parent.postMessage(message, targetOrigin)`
268
+ - Receives messages via `window.postMessage` events
269
+
270
+ ### NullTransport
271
+
272
+ Fallback transport that performs no operations. Used when no other transport is available (e.g., SSR, testing).
273
+
274
+ **Priority:** Always available (fallback)
275
+
276
+ ```typescript
277
+ import { NullTransport } from '@aspectly/transports';
278
+
279
+ const transport = new NullTransport();
280
+ transport.isAvailable(); // true
281
+ transport.send('message'); // No-op (logs warning in development)
282
+ transport.subscribe(() => {}); // Returns no-op cleanup function
283
+ ```
284
+
285
+ **Behavior:**
286
+ - `isAvailable()` always returns `true`
287
+ - `send()` is a no-op (logs warning in development mode)
288
+ - `subscribe()` returns a no-op cleanup function
289
+
290
+ ## Creating Custom Transports
291
+
292
+ ### Example: Electron Transport
293
+
294
+ ```typescript
295
+ import { BaseTransport, registerTransport } from '@aspectly/transports';
296
+ import type { TransportListener, TransportUnsubscribe } from '@aspectly/transports';
297
+
298
+ // Extend BaseTransport for helper methods
299
+ class ElectronTransport extends BaseTransport {
300
+ readonly name = 'electron';
301
+
302
+ isAvailable(): boolean {
303
+ const win = this.getWindow();
304
+ return typeof win?.electron?.send === 'function';
305
+ }
306
+
307
+ send(message: string): void {
308
+ const win = this.getWindow();
309
+ if (!win?.electron?.send) {
310
+ console.warn('[ElectronTransport] electron.send not available');
311
+ return;
312
+ }
313
+ win.electron.send('message', message);
314
+ }
315
+
316
+ subscribe(listener: TransportListener): TransportUnsubscribe {
317
+ const win = this.getWindow();
318
+ if (!win?.electron?.on) {
319
+ return () => {};
320
+ }
321
+
322
+ const handler = (_event: any, message: string) => {
323
+ listener(message);
324
+ };
325
+
326
+ win.electron.on('message', handler);
327
+ return () => {
328
+ win.electron?.removeListener('message', handler);
329
+ };
330
+ }
331
+ }
332
+
333
+ // Register with high priority
334
+ registerTransport({
335
+ name: 'electron',
336
+ priority: 150,
337
+ detect: () => {
338
+ return typeof window !== 'undefined' &&
339
+ window.electron?.send !== undefined;
340
+ },
341
+ createTransport: () => new ElectronTransport(),
342
+ });
343
+ ```
344
+
345
+ ### Implementation Checklist
346
+
347
+ When creating a custom transport:
348
+
349
+ 1. ✓ Extend `BaseTransport` or implement `Transport` interface
350
+ 2. ✓ Provide unique `name` property
351
+ 3. ✓ Implement `isAvailable()` to check environment
352
+ 4. ✓ Implement `send()` to send messages
353
+ 5. ✓ Implement `subscribe()` to receive messages
354
+ 6. ✓ Return cleanup function from `subscribe()`
355
+ 7. ✓ Handle SSR/missing globals safely
356
+ 8. ✓ Create a `TransportDetector` for registration
357
+ 9. ✓ Set appropriate `priority` (higher = checked first)
358
+
359
+ ## Related Packages
360
+
361
+ - [`@aspectly/core`](../core) - Core bridge protocol and message handling
362
+ - [`@aspectly/web`](../web) - Web/iframe integration with React hooks
363
+ - [`@aspectly/react-native`](../react-native) - React Native WebView integration
364
+ - [`@aspectly/react-native-web`](../react-native-web) - Universal React Native Web support
365
+
366
+ ## License
367
+
368
+ MIT
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Message listener callback type
3
+ */
4
+ type TransportListener = (message: string) => void;
5
+ /**
6
+ * Cleanup function returned by subscribe
7
+ */
8
+ type TransportUnsubscribe = () => void;
9
+ /**
10
+ * Transport interface - defines how messages are sent and received
11
+ * between different environments (CefSharp, React Native, iframe, etc.)
12
+ */
13
+ interface Transport {
14
+ /**
15
+ * Unique name of the transport (e.g., 'cefsharp', 'react-native', 'iframe')
16
+ */
17
+ readonly name: string;
18
+ /**
19
+ * Check if this transport is available in the current environment
20
+ */
21
+ isAvailable(): boolean;
22
+ /**
23
+ * Send a message to the parent/host context
24
+ * @param message Serialized message string (usually JSON)
25
+ */
26
+ send(message: string): void;
27
+ /**
28
+ * Subscribe to incoming messages from the parent/host context
29
+ * @param listener Callback function for incoming messages
30
+ * @returns Cleanup function to unsubscribe
31
+ */
32
+ subscribe(listener: TransportListener): TransportUnsubscribe;
33
+ }
34
+ /**
35
+ * Transport factory function type
36
+ */
37
+ type TransportFactory = () => Transport;
38
+ /**
39
+ * Transport detector - used for auto-detection
40
+ */
41
+ interface TransportDetector {
42
+ /**
43
+ * Name of the transport this detector is for
44
+ */
45
+ readonly name: string;
46
+ /**
47
+ * Priority for detection order (higher = checked first)
48
+ * Default priorities: CefSharp=100, ReactNative=90, Iframe=80
49
+ */
50
+ readonly priority: number;
51
+ /**
52
+ * Check if this transport is available
53
+ */
54
+ detect(): boolean;
55
+ /**
56
+ * Create the transport instance
57
+ */
58
+ createTransport(): Transport;
59
+ }
60
+
61
+ /**
62
+ * Abstract base class for transports
63
+ * Provides common functionality for message handling
64
+ */
65
+ declare abstract class BaseTransport implements Transport {
66
+ abstract readonly name: string;
67
+ abstract isAvailable(): boolean;
68
+ abstract send(message: string): void;
69
+ abstract subscribe(listener: TransportListener): TransportUnsubscribe;
70
+ /**
71
+ * Helper to check if window is defined (for SSR safety)
72
+ */
73
+ protected hasWindow(): boolean;
74
+ /**
75
+ * Helper to safely get window object
76
+ */
77
+ protected getWindow(): Window | null;
78
+ }
79
+
80
+ export { BaseTransport as B, type TransportListener as T, type TransportUnsubscribe as a, type TransportDetector as b, type Transport as c, type TransportFactory as d };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Message listener callback type
3
+ */
4
+ type TransportListener = (message: string) => void;
5
+ /**
6
+ * Cleanup function returned by subscribe
7
+ */
8
+ type TransportUnsubscribe = () => void;
9
+ /**
10
+ * Transport interface - defines how messages are sent and received
11
+ * between different environments (CefSharp, React Native, iframe, etc.)
12
+ */
13
+ interface Transport {
14
+ /**
15
+ * Unique name of the transport (e.g., 'cefsharp', 'react-native', 'iframe')
16
+ */
17
+ readonly name: string;
18
+ /**
19
+ * Check if this transport is available in the current environment
20
+ */
21
+ isAvailable(): boolean;
22
+ /**
23
+ * Send a message to the parent/host context
24
+ * @param message Serialized message string (usually JSON)
25
+ */
26
+ send(message: string): void;
27
+ /**
28
+ * Subscribe to incoming messages from the parent/host context
29
+ * @param listener Callback function for incoming messages
30
+ * @returns Cleanup function to unsubscribe
31
+ */
32
+ subscribe(listener: TransportListener): TransportUnsubscribe;
33
+ }
34
+ /**
35
+ * Transport factory function type
36
+ */
37
+ type TransportFactory = () => Transport;
38
+ /**
39
+ * Transport detector - used for auto-detection
40
+ */
41
+ interface TransportDetector {
42
+ /**
43
+ * Name of the transport this detector is for
44
+ */
45
+ readonly name: string;
46
+ /**
47
+ * Priority for detection order (higher = checked first)
48
+ * Default priorities: CefSharp=100, ReactNative=90, Iframe=80
49
+ */
50
+ readonly priority: number;
51
+ /**
52
+ * Check if this transport is available
53
+ */
54
+ detect(): boolean;
55
+ /**
56
+ * Create the transport instance
57
+ */
58
+ createTransport(): Transport;
59
+ }
60
+
61
+ /**
62
+ * Abstract base class for transports
63
+ * Provides common functionality for message handling
64
+ */
65
+ declare abstract class BaseTransport implements Transport {
66
+ abstract readonly name: string;
67
+ abstract isAvailable(): boolean;
68
+ abstract send(message: string): void;
69
+ abstract subscribe(listener: TransportListener): TransportUnsubscribe;
70
+ /**
71
+ * Helper to check if window is defined (for SSR safety)
72
+ */
73
+ protected hasWindow(): boolean;
74
+ /**
75
+ * Helper to safely get window object
76
+ */
77
+ protected getWindow(): Window | null;
78
+ }
79
+
80
+ export { BaseTransport as B, type TransportListener as T, type TransportUnsubscribe as a, type TransportDetector as b, type Transport as c, type TransportFactory as d };
@@ -0,0 +1,37 @@
1
+ import { B as BaseTransport, T as TransportListener, a as TransportUnsubscribe, b as TransportDetector } from './BaseTransport-CxzIr1Ds.mjs';
2
+ export { c as Transport } from './BaseTransport-CxzIr1Ds.mjs';
3
+
4
+ declare global {
5
+ interface Window {
6
+ CefSharp?: {
7
+ PostMessage: (message: string) => void;
8
+ BindObjectAsync: (...args: unknown[]) => Promise<void>;
9
+ };
10
+ }
11
+ }
12
+ /**
13
+ * Transport for CefSharp (Chromium Embedded Framework for .NET)
14
+ * Used in desktop applications with embedded Chromium browsers
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { CefSharpTransport } from '@aspectly/transports/cefsharp';
19
+ *
20
+ * const transport = new CefSharpTransport();
21
+ * if (transport.isAvailable()) {
22
+ * transport.send(JSON.stringify({ type: 'hello' }));
23
+ * }
24
+ * ```
25
+ */
26
+ declare class CefSharpTransport extends BaseTransport {
27
+ readonly name = "cefsharp";
28
+ isAvailable(): boolean;
29
+ send(message: string): void;
30
+ subscribe(listener: TransportListener): TransportUnsubscribe;
31
+ }
32
+ /**
33
+ * Detector for auto-detection registry
34
+ */
35
+ declare const cefSharpDetector: TransportDetector;
36
+
37
+ export { CefSharpTransport, TransportListener, TransportUnsubscribe, cefSharpDetector };
@@ -0,0 +1,37 @@
1
+ import { B as BaseTransport, T as TransportListener, a as TransportUnsubscribe, b as TransportDetector } from './BaseTransport-CxzIr1Ds.js';
2
+ export { c as Transport } from './BaseTransport-CxzIr1Ds.js';
3
+
4
+ declare global {
5
+ interface Window {
6
+ CefSharp?: {
7
+ PostMessage: (message: string) => void;
8
+ BindObjectAsync: (...args: unknown[]) => Promise<void>;
9
+ };
10
+ }
11
+ }
12
+ /**
13
+ * Transport for CefSharp (Chromium Embedded Framework for .NET)
14
+ * Used in desktop applications with embedded Chromium browsers
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { CefSharpTransport } from '@aspectly/transports/cefsharp';
19
+ *
20
+ * const transport = new CefSharpTransport();
21
+ * if (transport.isAvailable()) {
22
+ * transport.send(JSON.stringify({ type: 'hello' }));
23
+ * }
24
+ * ```
25
+ */
26
+ declare class CefSharpTransport extends BaseTransport {
27
+ readonly name = "cefsharp";
28
+ isAvailable(): boolean;
29
+ send(message: string): void;
30
+ subscribe(listener: TransportListener): TransportUnsubscribe;
31
+ }
32
+ /**
33
+ * Detector for auto-detection registry
34
+ */
35
+ declare const cefSharpDetector: TransportDetector;
36
+
37
+ export { CefSharpTransport, TransportListener, TransportUnsubscribe, cefSharpDetector };
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ // src/BaseTransport.ts
4
+ var BaseTransport = class {
5
+ /**
6
+ * Helper to check if window is defined (for SSR safety)
7
+ */
8
+ hasWindow() {
9
+ return typeof window !== "undefined";
10
+ }
11
+ /**
12
+ * Helper to safely get window object
13
+ */
14
+ getWindow() {
15
+ return this.hasWindow() ? window : null;
16
+ }
17
+ };
18
+
19
+ // src/transports/CefSharpTransport.ts
20
+ var CefSharpTransport = class extends BaseTransport {
21
+ constructor() {
22
+ super(...arguments);
23
+ this.name = "cefsharp";
24
+ }
25
+ isAvailable() {
26
+ const win = this.getWindow();
27
+ return typeof win?.CefSharp?.PostMessage === "function";
28
+ }
29
+ send(message) {
30
+ const win = this.getWindow();
31
+ if (!win?.CefSharp?.PostMessage) {
32
+ console.warn("[CefSharpTransport] CefSharp.PostMessage is not available");
33
+ return;
34
+ }
35
+ win.CefSharp.PostMessage(message);
36
+ }
37
+ subscribe(listener) {
38
+ const win = this.getWindow();
39
+ if (!win) {
40
+ return () => {
41
+ };
42
+ }
43
+ const handler = (event) => {
44
+ if (typeof event.data === "string") {
45
+ listener(event.data);
46
+ }
47
+ };
48
+ win.addEventListener("message", handler);
49
+ return () => win.removeEventListener("message", handler);
50
+ }
51
+ };
52
+ var cefSharpDetector = {
53
+ name: "cefsharp",
54
+ priority: 100,
55
+ // Highest priority - check first
56
+ detect: () => {
57
+ return typeof window !== "undefined" && typeof window.CefSharp?.PostMessage === "function";
58
+ },
59
+ createTransport: () => new CefSharpTransport()
60
+ };
61
+
62
+ exports.CefSharpTransport = CefSharpTransport;
63
+ exports.cefSharpDetector = cefSharpDetector;
64
+ //# sourceMappingURL=cefsharp.js.map
65
+ //# sourceMappingURL=cefsharp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/BaseTransport.ts","../src/transports/CefSharpTransport.ts"],"names":[],"mappings":";;;AAMO,IAAe,gBAAf,MAAkD;AAAA;AAAA;AAAA;AAAA,EAU7C,SAAA,GAAqB;AAC7B,IAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKU,SAAA,GAA2B;AACnC,IAAA,OAAO,IAAA,CAAK,SAAA,EAAU,GAAI,MAAA,GAAS,IAAA;AAAA,EACrC;AACF,CAAA;;;ACAO,IAAM,iBAAA,GAAN,cAAgC,aAAA,CAAc;AAAA,EAA9C,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AACL,IAAA,IAAA,CAAS,IAAA,GAAO,UAAA;AAAA,EAAA;AAAA,EAEhB,WAAA,GAAuB;AACrB,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,OAAO,OAAO,GAAA,EAAK,QAAA,EAAU,WAAA,KAAgB,UAAA;AAAA,EAC/C;AAAA,EAEA,KAAK,OAAA,EAAuB;AAC1B,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK,QAAA,EAAU,WAAA,EAAa;AAC/B,MAAA,OAAA,CAAQ,KAAK,2DAA2D,CAAA;AACxE,MAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,QAAA,CAAS,YAAY,OAAO,CAAA;AAAA,EAClC;AAAA,EAEA,UAAU,QAAA,EAAmD;AAC3D,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,OAAO,MAAM;AAAA,MAAC,CAAA;AAAA,IAChB;AAGA,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAA8B;AAC7C,MAAA,IAAI,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,EAAU;AAClC,QAAA,QAAA,CAAS,MAAM,IAAI,CAAA;AAAA,MACrB;AAAA,IACF,CAAA;AAEA,IAAA,GAAA,CAAI,gBAAA,CAAiB,WAAW,OAAO,CAAA;AACvC,IAAA,OAAO,MAAM,GAAA,CAAI,mBAAA,CAAoB,SAAA,EAAW,OAAO,CAAA;AAAA,EACzD;AACF;AAKO,IAAM,gBAAA,GAAsC;AAAA,EACjD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,GAAA;AAAA;AAAA,EACV,QAAQ,MAAM;AACZ,IAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,MAAA,CAAO,UAAU,WAAA,KAAgB,UAAA;AAAA,EACjD,CAAA;AAAA,EACA,eAAA,EAAiB,MAAM,IAAI,iBAAA;AAC7B","file":"cefsharp.js","sourcesContent":["import type { Transport, TransportListener, TransportUnsubscribe } from './types';\r\n\r\n/**\r\n * Abstract base class for transports\r\n * Provides common functionality for message handling\r\n */\r\nexport abstract class BaseTransport implements Transport {\r\n abstract readonly name: string;\r\n\r\n abstract isAvailable(): boolean;\r\n abstract send(message: string): void;\r\n abstract subscribe(listener: TransportListener): TransportUnsubscribe;\r\n\r\n /**\r\n * Helper to check if window is defined (for SSR safety)\r\n */\r\n protected hasWindow(): boolean {\r\n return typeof window !== 'undefined';\r\n }\r\n\r\n /**\r\n * Helper to safely get window object\r\n */\r\n protected getWindow(): Window | null {\r\n return this.hasWindow() ? window : null;\r\n }\r\n}\r\n","import { BaseTransport } from '../BaseTransport';\r\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\r\n\r\ndeclare global {\r\n interface Window {\r\n CefSharp?: {\r\n PostMessage: (message: string) => void;\r\n BindObjectAsync: (...args: unknown[]) => Promise<void>;\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transport for CefSharp (Chromium Embedded Framework for .NET)\r\n * Used in desktop applications with embedded Chromium browsers\r\n *\r\n * @example\r\n * ```typescript\r\n * import { CefSharpTransport } from '@aspectly/transports/cefsharp';\r\n *\r\n * const transport = new CefSharpTransport();\r\n * if (transport.isAvailable()) {\r\n * transport.send(JSON.stringify({ type: 'hello' }));\r\n * }\r\n * ```\r\n */\r\nexport class CefSharpTransport extends BaseTransport {\r\n readonly name = 'cefsharp';\r\n\r\n isAvailable(): boolean {\r\n const win = this.getWindow();\r\n return typeof win?.CefSharp?.PostMessage === 'function';\r\n }\r\n\r\n send(message: string): void {\r\n const win = this.getWindow();\r\n if (!win?.CefSharp?.PostMessage) {\r\n console.warn('[CefSharpTransport] CefSharp.PostMessage is not available');\r\n return;\r\n }\r\n win.CefSharp.PostMessage(message);\r\n }\r\n\r\n subscribe(listener: TransportListener): TransportUnsubscribe {\r\n const win = this.getWindow();\r\n if (!win) {\r\n return () => {};\r\n }\r\n\r\n // CefSharp sends messages via window.postMessage\r\n const handler = (event: MessageEvent): void => {\r\n if (typeof event.data === 'string') {\r\n listener(event.data);\r\n }\r\n };\r\n\r\n win.addEventListener('message', handler);\r\n return () => win.removeEventListener('message', handler);\r\n }\r\n}\r\n\r\n/**\r\n * Detector for auto-detection registry\r\n */\r\nexport const cefSharpDetector: TransportDetector = {\r\n name: 'cefsharp',\r\n priority: 100, // Highest priority - check first\r\n detect: () => {\r\n return typeof window !== 'undefined' &&\r\n typeof window.CefSharp?.PostMessage === 'function';\r\n },\r\n createTransport: () => new CefSharpTransport(),\r\n};\r\n"]}