@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
@@ -0,0 +1,73 @@
1
+ import { BaseTransport } from '../BaseTransport';
2
+ import type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';
3
+
4
+ declare global {
5
+ interface Window {
6
+ ReactNativeWebView?: {
7
+ postMessage: (message: string) => void;
8
+ };
9
+ }
10
+ }
11
+
12
+ /**
13
+ * Transport for React Native WebView
14
+ * Used when web content is displayed inside a React Native app
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { ReactNativeTransport } from '@aspectly/transports/react-native';
19
+ *
20
+ * const transport = new ReactNativeTransport();
21
+ * if (transport.isAvailable()) {
22
+ * transport.send(JSON.stringify({ type: 'hello' }));
23
+ * }
24
+ * ```
25
+ */
26
+ export class ReactNativeTransport extends BaseTransport {
27
+ readonly name = 'react-native';
28
+
29
+ isAvailable(): boolean {
30
+ const win = this.getWindow();
31
+ return typeof win?.ReactNativeWebView?.postMessage === 'function';
32
+ }
33
+
34
+ send(message: string): void {
35
+ const win = this.getWindow();
36
+ if (!win?.ReactNativeWebView?.postMessage) {
37
+ console.warn('[ReactNativeTransport] ReactNativeWebView.postMessage is not available');
38
+ return;
39
+ }
40
+ // React Native WebView expects message wrapped in quotes (iOS quirk)
41
+ win.ReactNativeWebView.postMessage(`'${message}'`);
42
+ }
43
+
44
+ subscribe(listener: TransportListener): TransportUnsubscribe {
45
+ const win = this.getWindow();
46
+ if (!win) {
47
+ return () => {};
48
+ }
49
+
50
+ // React Native sends messages via window.postMessage
51
+ const handler = (event: MessageEvent): void => {
52
+ if (typeof event.data === 'string') {
53
+ listener(event.data);
54
+ }
55
+ };
56
+
57
+ win.addEventListener('message', handler);
58
+ return () => win.removeEventListener('message', handler);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Detector for auto-detection registry
64
+ */
65
+ export const reactNativeDetector: TransportDetector = {
66
+ name: 'react-native',
67
+ priority: 90, // Second priority
68
+ detect: () => {
69
+ return typeof window !== 'undefined' &&
70
+ typeof window.ReactNativeWebView?.postMessage === 'function';
71
+ },
72
+ createTransport: () => new ReactNativeTransport(),
73
+ };
@@ -0,0 +1,84 @@
1
+ import { BaseTransport } from '../BaseTransport';
2
+ import type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';
3
+
4
+ /**
5
+ * Transport for popup windows opened via window.open()
6
+ * Used when web content is displayed in a child window
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // In child window (opened via window.open())
11
+ * import { WindowTransport } from '@aspectly/transports/window';
12
+ *
13
+ * const transport = new WindowTransport();
14
+ * if (transport.isAvailable()) {
15
+ * transport.send(JSON.stringify({ type: 'hello' }));
16
+ * }
17
+ * ```
18
+ */
19
+ export class WindowTransport extends BaseTransport {
20
+ readonly name = 'window';
21
+ private readonly targetOrigin: string;
22
+
23
+ /**
24
+ * Create a window transport
25
+ * @param targetOrigin Origin to send messages to (default: '*')
26
+ */
27
+ constructor(targetOrigin: string = '*') {
28
+ super();
29
+ this.targetOrigin = targetOrigin;
30
+ }
31
+
32
+ isAvailable(): boolean {
33
+ const win = this.getWindow();
34
+ if (!win) return false;
35
+ return win.opener !== null && !win.opener.closed;
36
+ }
37
+
38
+ send(message: string): void {
39
+ const win = this.getWindow();
40
+ if (!win) {
41
+ console.warn('[WindowTransport] Window is not available');
42
+ return;
43
+ }
44
+ if (!win.opener || win.opener.closed) {
45
+ console.warn('[WindowTransport] Opener window is not available');
46
+ return;
47
+ }
48
+ win.opener.postMessage(message, this.targetOrigin);
49
+ }
50
+
51
+ subscribe(listener: TransportListener): TransportUnsubscribe {
52
+ const win = this.getWindow();
53
+ if (!win) {
54
+ return () => {};
55
+ }
56
+
57
+ const handler = (event: MessageEvent): void => {
58
+ if (typeof event.data === 'string') {
59
+ listener(event.data);
60
+ }
61
+ };
62
+
63
+ win.addEventListener('message', handler);
64
+ return () => win.removeEventListener('message', handler);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Detector for auto-detection registry
70
+ */
71
+ export const windowDetector: TransportDetector = {
72
+ name: 'window',
73
+ priority: 70, // Below iframe (80), above postmessage (10)
74
+ detect: () => {
75
+ try {
76
+ return typeof window !== 'undefined' &&
77
+ window.opener != null &&
78
+ !window.opener.closed;
79
+ } catch {
80
+ return false;
81
+ }
82
+ },
83
+ createTransport: () => new WindowTransport(),
84
+ };
package/src/types.ts ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Message listener callback type
3
+ */
4
+ export type TransportListener = (message: string) => void;
5
+
6
+ /**
7
+ * Cleanup function returned by subscribe
8
+ */
9
+ export type TransportUnsubscribe = () => void;
10
+
11
+ /**
12
+ * Transport interface - defines how messages are sent and received
13
+ * between different environments (CefSharp, React Native, iframe, etc.)
14
+ */
15
+ export interface Transport {
16
+ /**
17
+ * Unique name of the transport (e.g., 'cefsharp', 'react-native', 'iframe')
18
+ */
19
+ readonly name: string;
20
+
21
+ /**
22
+ * Check if this transport is available in the current environment
23
+ */
24
+ isAvailable(): boolean;
25
+
26
+ /**
27
+ * Send a message to the parent/host context
28
+ * @param message Serialized message string (usually JSON)
29
+ */
30
+ send(message: string): void;
31
+
32
+ /**
33
+ * Subscribe to incoming messages from the parent/host context
34
+ * @param listener Callback function for incoming messages
35
+ * @returns Cleanup function to unsubscribe
36
+ */
37
+ subscribe(listener: TransportListener): TransportUnsubscribe;
38
+ }
39
+
40
+ /**
41
+ * Transport factory function type
42
+ */
43
+ export type TransportFactory = () => Transport;
44
+
45
+ /**
46
+ * Transport detector - used for auto-detection
47
+ */
48
+ export interface TransportDetector {
49
+ /**
50
+ * Name of the transport this detector is for
51
+ */
52
+ readonly name: string;
53
+
54
+ /**
55
+ * Priority for detection order (higher = checked first)
56
+ * Default priorities: CefSharp=100, ReactNative=90, Iframe=80
57
+ */
58
+ readonly priority: number;
59
+
60
+ /**
61
+ * Check if this transport is available
62
+ */
63
+ detect(): boolean;
64
+
65
+ /**
66
+ * Create the transport instance
67
+ */
68
+ createTransport(): Transport;
69
+ }
package/src/window.ts ADDED
@@ -0,0 +1,3 @@
1
+ // Window transport - standalone entry point
2
+ export { WindowTransport, windowDetector } from './transports/WindowTransport';
3
+ export type { Transport, TransportListener, TransportUnsubscribe } from './types';