@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.
- package/LICENSE +20 -0
- package/README.md +368 -0
- package/dist/BaseTransport-CxzIr1Ds.d.mts +80 -0
- package/dist/BaseTransport-CxzIr1Ds.d.ts +80 -0
- package/dist/cefsharp.d.mts +37 -0
- package/dist/cefsharp.d.ts +37 -0
- package/dist/cefsharp.js +65 -0
- package/dist/cefsharp.js.map +1 -0
- package/dist/cefsharp.mjs +62 -0
- package/dist/cefsharp.mjs.map +1 -0
- package/dist/iframe.d.mts +35 -0
- package/dist/iframe.d.ts +35 -0
- package/dist/iframe.js +75 -0
- package/dist/iframe.js.map +1 -0
- package/dist/iframe.mjs +72 -0
- package/dist/iframe.mjs.map +1 -0
- package/dist/index.d.mts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +374 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +358 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react-native.d.mts +36 -0
- package/dist/react-native.d.ts +36 -0
- package/dist/react-native.js +65 -0
- package/dist/react-native.js.map +1 -0
- package/dist/react-native.mjs +62 -0
- package/dist/react-native.mjs.map +1 -0
- package/dist/window.d.mts +36 -0
- package/dist/window.d.ts +36 -0
- package/dist/window.js +79 -0
- package/dist/window.js.map +1 -0
- package/dist/window.mjs +76 -0
- package/dist/window.mjs.map +1 -0
- package/package.json +97 -0
- package/src/BaseTransport.test.ts +60 -0
- package/src/BaseTransport.ts +27 -0
- package/src/TransportRegistry.test.ts +345 -0
- package/src/TransportRegistry.ts +120 -0
- package/src/cefsharp.ts +3 -0
- package/src/iframe.ts +3 -0
- package/src/index.ts +26 -0
- package/src/react-native.ts +3 -0
- package/src/transports/CefSharpTransport.test.ts +187 -0
- package/src/transports/CefSharpTransport.ts +73 -0
- package/src/transports/IframeTransport.test.ts +212 -0
- package/src/transports/IframeTransport.ts +79 -0
- package/src/transports/NullTransport.test.ts +64 -0
- package/src/transports/NullTransport.ts +27 -0
- package/src/transports/PostMessageTransport.ts +50 -0
- package/src/transports/ReactNativeTransport.test.ts +196 -0
- package/src/transports/ReactNativeTransport.ts +73 -0
- package/src/transports/WindowTransport.ts +84 -0
- package/src/types.ts +69 -0
- package/src/window.ts +3 -0
package/dist/window.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
/**
|
|
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
|
+
declare class WindowTransport extends BaseTransport {
|
|
20
|
+
readonly name = "window";
|
|
21
|
+
private readonly targetOrigin;
|
|
22
|
+
/**
|
|
23
|
+
* Create a window transport
|
|
24
|
+
* @param targetOrigin Origin to send messages to (default: '*')
|
|
25
|
+
*/
|
|
26
|
+
constructor(targetOrigin?: string);
|
|
27
|
+
isAvailable(): boolean;
|
|
28
|
+
send(message: string): void;
|
|
29
|
+
subscribe(listener: TransportListener): TransportUnsubscribe;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Detector for auto-detection registry
|
|
33
|
+
*/
|
|
34
|
+
declare const windowDetector: TransportDetector;
|
|
35
|
+
|
|
36
|
+
export { TransportListener, TransportUnsubscribe, WindowTransport, windowDetector };
|
package/dist/window.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
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/WindowTransport.ts
|
|
20
|
+
var WindowTransport = class extends BaseTransport {
|
|
21
|
+
/**
|
|
22
|
+
* Create a window transport
|
|
23
|
+
* @param targetOrigin Origin to send messages to (default: '*')
|
|
24
|
+
*/
|
|
25
|
+
constructor(targetOrigin = "*") {
|
|
26
|
+
super();
|
|
27
|
+
this.name = "window";
|
|
28
|
+
this.targetOrigin = targetOrigin;
|
|
29
|
+
}
|
|
30
|
+
isAvailable() {
|
|
31
|
+
const win = this.getWindow();
|
|
32
|
+
if (!win) return false;
|
|
33
|
+
return win.opener !== null && !win.opener.closed;
|
|
34
|
+
}
|
|
35
|
+
send(message) {
|
|
36
|
+
const win = this.getWindow();
|
|
37
|
+
if (!win) {
|
|
38
|
+
console.warn("[WindowTransport] Window is not available");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!win.opener || win.opener.closed) {
|
|
42
|
+
console.warn("[WindowTransport] Opener window is not available");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
win.opener.postMessage(message, this.targetOrigin);
|
|
46
|
+
}
|
|
47
|
+
subscribe(listener) {
|
|
48
|
+
const win = this.getWindow();
|
|
49
|
+
if (!win) {
|
|
50
|
+
return () => {
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const handler = (event) => {
|
|
54
|
+
if (typeof event.data === "string") {
|
|
55
|
+
listener(event.data);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
win.addEventListener("message", handler);
|
|
59
|
+
return () => win.removeEventListener("message", handler);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var windowDetector = {
|
|
63
|
+
name: "window",
|
|
64
|
+
priority: 70,
|
|
65
|
+
// Below iframe (80), above postmessage (10)
|
|
66
|
+
detect: () => {
|
|
67
|
+
try {
|
|
68
|
+
return typeof window !== "undefined" && window.opener != null && !window.opener.closed;
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
createTransport: () => new WindowTransport()
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
exports.WindowTransport = WindowTransport;
|
|
77
|
+
exports.windowDetector = windowDetector;
|
|
78
|
+
//# sourceMappingURL=window.js.map
|
|
79
|
+
//# sourceMappingURL=window.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/BaseTransport.ts","../src/transports/WindowTransport.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;;;ACRO,IAAM,eAAA,GAAN,cAA8B,aAAA,CAAc;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjD,WAAA,CAAY,eAAuB,GAAA,EAAK;AACtC,IAAA,KAAA,EAAM;AARR,IAAA,IAAA,CAAS,IAAA,GAAO,QAAA;AASd,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA;AAAA,EACtB;AAAA,EAEA,WAAA,GAAuB;AACrB,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,KAAK,OAAO,KAAA;AACjB,IAAA,OAAO,GAAA,CAAI,MAAA,KAAW,IAAA,IAAQ,CAAC,IAAI,MAAA,CAAO,MAAA;AAAA,EAC5C;AAAA,EAEA,KAAK,OAAA,EAAuB;AAC1B,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,OAAA,CAAQ,KAAK,2CAA2C,CAAA;AACxD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,GAAA,CAAI,MAAA,IAAU,GAAA,CAAI,OAAO,MAAA,EAAQ;AACpC,MAAA,OAAA,CAAQ,KAAK,kDAAkD,CAAA;AAC/D,MAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,MAAA,CAAO,WAAA,CAAY,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,EACnD;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;AAEA,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,cAAA,GAAoC;AAAA,EAC/C,IAAA,EAAM,QAAA;AAAA,EACN,QAAA,EAAU,EAAA;AAAA;AAAA,EACV,QAAQ,MAAM;AACZ,IAAA,IAAI;AACF,MAAA,OAAO,OAAO,WAAW,WAAA,IACvB,MAAA,CAAO,UAAU,IAAA,IACjB,CAAC,OAAO,MAAA,CAAO,MAAA;AAAA,IACnB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,eAAA,EAAiB,MAAM,IAAI,eAAA;AAC7B","file":"window.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';\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\n\n/**\n * Transport for popup windows opened via window.open()\n * Used when web content is displayed in a child window\n *\n * @example\n * ```typescript\n * // In child window (opened via window.open())\n * import { WindowTransport } from '@aspectly/transports/window';\n *\n * const transport = new WindowTransport();\n * if (transport.isAvailable()) {\n * transport.send(JSON.stringify({ type: 'hello' }));\n * }\n * ```\n */\nexport class WindowTransport extends BaseTransport {\n readonly name = 'window';\n private readonly targetOrigin: string;\n\n /**\n * Create a window transport\n * @param targetOrigin Origin to send messages to (default: '*')\n */\n constructor(targetOrigin: string = '*') {\n super();\n this.targetOrigin = targetOrigin;\n }\n\n isAvailable(): boolean {\n const win = this.getWindow();\n if (!win) return false;\n return win.opener !== null && !win.opener.closed;\n }\n\n send(message: string): void {\n const win = this.getWindow();\n if (!win) {\n console.warn('[WindowTransport] Window is not available');\n return;\n }\n if (!win.opener || win.opener.closed) {\n console.warn('[WindowTransport] Opener window is not available');\n return;\n }\n win.opener.postMessage(message, this.targetOrigin);\n }\n\n subscribe(listener: TransportListener): TransportUnsubscribe {\n const win = this.getWindow();\n if (!win) {\n return () => {};\n }\n\n const handler = (event: MessageEvent): void => {\n if (typeof event.data === 'string') {\n listener(event.data);\n }\n };\n\n win.addEventListener('message', handler);\n return () => win.removeEventListener('message', handler);\n }\n}\n\n/**\n * Detector for auto-detection registry\n */\nexport const windowDetector: TransportDetector = {\n name: 'window',\n priority: 70, // Below iframe (80), above postmessage (10)\n detect: () => {\n try {\n return typeof window !== 'undefined' &&\n window.opener != null &&\n !window.opener.closed;\n } catch {\n return false;\n }\n },\n createTransport: () => new WindowTransport(),\n};\n"]}
|
package/dist/window.mjs
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// src/BaseTransport.ts
|
|
2
|
+
var BaseTransport = class {
|
|
3
|
+
/**
|
|
4
|
+
* Helper to check if window is defined (for SSR safety)
|
|
5
|
+
*/
|
|
6
|
+
hasWindow() {
|
|
7
|
+
return typeof window !== "undefined";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Helper to safely get window object
|
|
11
|
+
*/
|
|
12
|
+
getWindow() {
|
|
13
|
+
return this.hasWindow() ? window : null;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/transports/WindowTransport.ts
|
|
18
|
+
var WindowTransport = class extends BaseTransport {
|
|
19
|
+
/**
|
|
20
|
+
* Create a window transport
|
|
21
|
+
* @param targetOrigin Origin to send messages to (default: '*')
|
|
22
|
+
*/
|
|
23
|
+
constructor(targetOrigin = "*") {
|
|
24
|
+
super();
|
|
25
|
+
this.name = "window";
|
|
26
|
+
this.targetOrigin = targetOrigin;
|
|
27
|
+
}
|
|
28
|
+
isAvailable() {
|
|
29
|
+
const win = this.getWindow();
|
|
30
|
+
if (!win) return false;
|
|
31
|
+
return win.opener !== null && !win.opener.closed;
|
|
32
|
+
}
|
|
33
|
+
send(message) {
|
|
34
|
+
const win = this.getWindow();
|
|
35
|
+
if (!win) {
|
|
36
|
+
console.warn("[WindowTransport] Window is not available");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (!win.opener || win.opener.closed) {
|
|
40
|
+
console.warn("[WindowTransport] Opener window is not available");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
win.opener.postMessage(message, this.targetOrigin);
|
|
44
|
+
}
|
|
45
|
+
subscribe(listener) {
|
|
46
|
+
const win = this.getWindow();
|
|
47
|
+
if (!win) {
|
|
48
|
+
return () => {
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const handler = (event) => {
|
|
52
|
+
if (typeof event.data === "string") {
|
|
53
|
+
listener(event.data);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
win.addEventListener("message", handler);
|
|
57
|
+
return () => win.removeEventListener("message", handler);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var windowDetector = {
|
|
61
|
+
name: "window",
|
|
62
|
+
priority: 70,
|
|
63
|
+
// Below iframe (80), above postmessage (10)
|
|
64
|
+
detect: () => {
|
|
65
|
+
try {
|
|
66
|
+
return typeof window !== "undefined" && window.opener != null && !window.opener.closed;
|
|
67
|
+
} catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
createTransport: () => new WindowTransport()
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export { WindowTransport, windowDetector };
|
|
75
|
+
//# sourceMappingURL=window.mjs.map
|
|
76
|
+
//# sourceMappingURL=window.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/BaseTransport.ts","../src/transports/WindowTransport.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;;;ACRO,IAAM,eAAA,GAAN,cAA8B,aAAA,CAAc;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjD,WAAA,CAAY,eAAuB,GAAA,EAAK;AACtC,IAAA,KAAA,EAAM;AARR,IAAA,IAAA,CAAS,IAAA,GAAO,QAAA;AASd,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA;AAAA,EACtB;AAAA,EAEA,WAAA,GAAuB;AACrB,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,KAAK,OAAO,KAAA;AACjB,IAAA,OAAO,GAAA,CAAI,MAAA,KAAW,IAAA,IAAQ,CAAC,IAAI,MAAA,CAAO,MAAA;AAAA,EAC5C;AAAA,EAEA,KAAK,OAAA,EAAuB;AAC1B,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,OAAA,CAAQ,KAAK,2CAA2C,CAAA;AACxD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,GAAA,CAAI,MAAA,IAAU,GAAA,CAAI,OAAO,MAAA,EAAQ;AACpC,MAAA,OAAA,CAAQ,KAAK,kDAAkD,CAAA;AAC/D,MAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,MAAA,CAAO,WAAA,CAAY,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,EACnD;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;AAEA,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,cAAA,GAAoC;AAAA,EAC/C,IAAA,EAAM,QAAA;AAAA,EACN,QAAA,EAAU,EAAA;AAAA;AAAA,EACV,QAAQ,MAAM;AACZ,IAAA,IAAI;AACF,MAAA,OAAO,OAAO,WAAW,WAAA,IACvB,MAAA,CAAO,UAAU,IAAA,IACjB,CAAC,OAAO,MAAA,CAAO,MAAA;AAAA,IACnB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,eAAA,EAAiB,MAAM,IAAI,eAAA;AAC7B","file":"window.mjs","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';\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\n\n/**\n * Transport for popup windows opened via window.open()\n * Used when web content is displayed in a child window\n *\n * @example\n * ```typescript\n * // In child window (opened via window.open())\n * import { WindowTransport } from '@aspectly/transports/window';\n *\n * const transport = new WindowTransport();\n * if (transport.isAvailable()) {\n * transport.send(JSON.stringify({ type: 'hello' }));\n * }\n * ```\n */\nexport class WindowTransport extends BaseTransport {\n readonly name = 'window';\n private readonly targetOrigin: string;\n\n /**\n * Create a window transport\n * @param targetOrigin Origin to send messages to (default: '*')\n */\n constructor(targetOrigin: string = '*') {\n super();\n this.targetOrigin = targetOrigin;\n }\n\n isAvailable(): boolean {\n const win = this.getWindow();\n if (!win) return false;\n return win.opener !== null && !win.opener.closed;\n }\n\n send(message: string): void {\n const win = this.getWindow();\n if (!win) {\n console.warn('[WindowTransport] Window is not available');\n return;\n }\n if (!win.opener || win.opener.closed) {\n console.warn('[WindowTransport] Opener window is not available');\n return;\n }\n win.opener.postMessage(message, this.targetOrigin);\n }\n\n subscribe(listener: TransportListener): TransportUnsubscribe {\n const win = this.getWindow();\n if (!win) {\n return () => {};\n }\n\n const handler = (event: MessageEvent): void => {\n if (typeof event.data === 'string') {\n listener(event.data);\n }\n };\n\n win.addEventListener('message', handler);\n return () => win.removeEventListener('message', handler);\n }\n}\n\n/**\n * Detector for auto-detection registry\n */\nexport const windowDetector: TransportDetector = {\n name: 'window',\n priority: 70, // Below iframe (80), above postmessage (10)\n detect: () => {\n try {\n return typeof window !== 'undefined' &&\n window.opener != null &&\n !window.opener.closed;\n } catch {\n return false;\n }\n },\n createTransport: () => new WindowTransport(),\n};\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aspectly/transports",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Transport layer for Aspectly bridge - platform detection and message passing",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"./cefsharp": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/cefsharp.d.mts",
|
|
22
|
+
"default": "./dist/cefsharp.mjs"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/cefsharp.d.ts",
|
|
26
|
+
"default": "./dist/cefsharp.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"./react-native": {
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/react-native.d.mts",
|
|
32
|
+
"default": "./dist/react-native.mjs"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./dist/react-native.d.ts",
|
|
36
|
+
"default": "./dist/react-native.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./iframe": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/iframe.d.mts",
|
|
42
|
+
"default": "./dist/iframe.mjs"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/iframe.d.ts",
|
|
46
|
+
"default": "./dist/iframe.js"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"./window": {
|
|
50
|
+
"import": {
|
|
51
|
+
"types": "./dist/window.d.mts",
|
|
52
|
+
"default": "./dist/window.mjs"
|
|
53
|
+
},
|
|
54
|
+
"require": {
|
|
55
|
+
"types": "./dist/window.d.ts",
|
|
56
|
+
"default": "./dist/window.js"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"files": [
|
|
61
|
+
"dist",
|
|
62
|
+
"src"
|
|
63
|
+
],
|
|
64
|
+
"sideEffects": false,
|
|
65
|
+
"keywords": [
|
|
66
|
+
"aspectly",
|
|
67
|
+
"bridge",
|
|
68
|
+
"transport",
|
|
69
|
+
"cefsharp",
|
|
70
|
+
"webview",
|
|
71
|
+
"iframe",
|
|
72
|
+
"postmessage"
|
|
73
|
+
],
|
|
74
|
+
"author": "Zhan Isaakian <jeanisahkyan@gmail.com>",
|
|
75
|
+
"license": "MIT",
|
|
76
|
+
"repository": {
|
|
77
|
+
"type": "git",
|
|
78
|
+
"url": "https://github.com/JeanIsahakyan/aspectly",
|
|
79
|
+
"directory": "packages/transports"
|
|
80
|
+
},
|
|
81
|
+
"publishConfig": {
|
|
82
|
+
"access": "public"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"tsup": "^8.0.1",
|
|
86
|
+
"typescript": "^5.3.2",
|
|
87
|
+
"rimraf": "^5.0.5"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"build": "tsup",
|
|
91
|
+
"dev": "tsup --watch",
|
|
92
|
+
"typecheck": "tsc --noEmit",
|
|
93
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
94
|
+
"clean": "rimraf dist",
|
|
95
|
+
"test": "vitest run"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { BaseTransport } from './BaseTransport';
|
|
3
|
+
import type { TransportListener, TransportUnsubscribe } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Concrete test implementation of BaseTransport
|
|
7
|
+
*/
|
|
8
|
+
class TestTransport extends BaseTransport {
|
|
9
|
+
readonly name = 'test';
|
|
10
|
+
|
|
11
|
+
isAvailable(): boolean {
|
|
12
|
+
return this.hasWindow();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
send(_message: string): void {
|
|
16
|
+
// No-op for testing
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
subscribe(_listener: TransportListener): TransportUnsubscribe {
|
|
20
|
+
return () => {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('BaseTransport', () => {
|
|
25
|
+
it('should have hasWindow() return true in jsdom environment', () => {
|
|
26
|
+
const transport = new TestTransport();
|
|
27
|
+
expect(transport.isAvailable()).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should have getWindow() return window object in jsdom environment', () => {
|
|
31
|
+
const transport = new TestTransport();
|
|
32
|
+
// Using any to access protected method for testing
|
|
33
|
+
const win = (transport as any).getWindow();
|
|
34
|
+
expect(win).toBe(window);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should require abstract name property', () => {
|
|
38
|
+
const transport = new TestTransport();
|
|
39
|
+
expect(transport.name).toBe('test');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should require abstract isAvailable method', () => {
|
|
43
|
+
const transport = new TestTransport();
|
|
44
|
+
expect(typeof transport.isAvailable).toBe('function');
|
|
45
|
+
expect(typeof transport.isAvailable()).toBe('boolean');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should require abstract send method', () => {
|
|
49
|
+
const transport = new TestTransport();
|
|
50
|
+
expect(typeof transport.send).toBe('function');
|
|
51
|
+
expect(() => transport.send('test')).not.toThrow();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should require abstract subscribe method', () => {
|
|
55
|
+
const transport = new TestTransport();
|
|
56
|
+
expect(typeof transport.subscribe).toBe('function');
|
|
57
|
+
const unsubscribe = transport.subscribe(() => {});
|
|
58
|
+
expect(typeof unsubscribe).toBe('function');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Transport, TransportListener, TransportUnsubscribe } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for transports
|
|
5
|
+
* Provides common functionality for message handling
|
|
6
|
+
*/
|
|
7
|
+
export abstract class BaseTransport implements Transport {
|
|
8
|
+
abstract readonly name: string;
|
|
9
|
+
|
|
10
|
+
abstract isAvailable(): boolean;
|
|
11
|
+
abstract send(message: string): void;
|
|
12
|
+
abstract subscribe(listener: TransportListener): TransportUnsubscribe;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Helper to check if window is defined (for SSR safety)
|
|
16
|
+
*/
|
|
17
|
+
protected hasWindow(): boolean {
|
|
18
|
+
return typeof window !== 'undefined';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Helper to safely get window object
|
|
23
|
+
*/
|
|
24
|
+
protected getWindow(): Window | null {
|
|
25
|
+
return this.hasWindow() ? window : null;
|
|
26
|
+
}
|
|
27
|
+
}
|