@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/index.mjs
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
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/CefSharpTransport.ts
|
|
18
|
+
var CefSharpTransport = class extends BaseTransport {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.name = "cefsharp";
|
|
22
|
+
}
|
|
23
|
+
isAvailable() {
|
|
24
|
+
const win = this.getWindow();
|
|
25
|
+
return typeof win?.CefSharp?.PostMessage === "function";
|
|
26
|
+
}
|
|
27
|
+
send(message) {
|
|
28
|
+
const win = this.getWindow();
|
|
29
|
+
if (!win?.CefSharp?.PostMessage) {
|
|
30
|
+
console.warn("[CefSharpTransport] CefSharp.PostMessage is not available");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
win.CefSharp.PostMessage(message);
|
|
34
|
+
}
|
|
35
|
+
subscribe(listener) {
|
|
36
|
+
const win = this.getWindow();
|
|
37
|
+
if (!win) {
|
|
38
|
+
return () => {
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const handler = (event) => {
|
|
42
|
+
if (typeof event.data === "string") {
|
|
43
|
+
listener(event.data);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
win.addEventListener("message", handler);
|
|
47
|
+
return () => win.removeEventListener("message", handler);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var cefSharpDetector = {
|
|
51
|
+
name: "cefsharp",
|
|
52
|
+
priority: 100,
|
|
53
|
+
// Highest priority - check first
|
|
54
|
+
detect: () => {
|
|
55
|
+
return typeof window !== "undefined" && typeof window.CefSharp?.PostMessage === "function";
|
|
56
|
+
},
|
|
57
|
+
createTransport: () => new CefSharpTransport()
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// src/transports/ReactNativeTransport.ts
|
|
61
|
+
var ReactNativeTransport = class extends BaseTransport {
|
|
62
|
+
constructor() {
|
|
63
|
+
super(...arguments);
|
|
64
|
+
this.name = "react-native";
|
|
65
|
+
}
|
|
66
|
+
isAvailable() {
|
|
67
|
+
const win = this.getWindow();
|
|
68
|
+
return typeof win?.ReactNativeWebView?.postMessage === "function";
|
|
69
|
+
}
|
|
70
|
+
send(message) {
|
|
71
|
+
const win = this.getWindow();
|
|
72
|
+
if (!win?.ReactNativeWebView?.postMessage) {
|
|
73
|
+
console.warn("[ReactNativeTransport] ReactNativeWebView.postMessage is not available");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
win.ReactNativeWebView.postMessage(`'${message}'`);
|
|
77
|
+
}
|
|
78
|
+
subscribe(listener) {
|
|
79
|
+
const win = this.getWindow();
|
|
80
|
+
if (!win) {
|
|
81
|
+
return () => {
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const handler = (event) => {
|
|
85
|
+
if (typeof event.data === "string") {
|
|
86
|
+
listener(event.data);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
win.addEventListener("message", handler);
|
|
90
|
+
return () => win.removeEventListener("message", handler);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var reactNativeDetector = {
|
|
94
|
+
name: "react-native",
|
|
95
|
+
priority: 90,
|
|
96
|
+
// Second priority
|
|
97
|
+
detect: () => {
|
|
98
|
+
return typeof window !== "undefined" && typeof window.ReactNativeWebView?.postMessage === "function";
|
|
99
|
+
},
|
|
100
|
+
createTransport: () => new ReactNativeTransport()
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/transports/IframeTransport.ts
|
|
104
|
+
var IframeTransport = class extends BaseTransport {
|
|
105
|
+
/**
|
|
106
|
+
* Create an iframe transport
|
|
107
|
+
* @param targetOrigin Origin to send messages to (default: '*')
|
|
108
|
+
*/
|
|
109
|
+
constructor(targetOrigin = "*") {
|
|
110
|
+
super();
|
|
111
|
+
this.name = "iframe";
|
|
112
|
+
this.targetOrigin = targetOrigin;
|
|
113
|
+
}
|
|
114
|
+
isAvailable() {
|
|
115
|
+
const win = this.getWindow();
|
|
116
|
+
if (!win) return false;
|
|
117
|
+
return win.parent !== win;
|
|
118
|
+
}
|
|
119
|
+
send(message) {
|
|
120
|
+
const win = this.getWindow();
|
|
121
|
+
if (!win) {
|
|
122
|
+
console.warn("[IframeTransport] Window is not available");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (win.parent === win) {
|
|
126
|
+
console.warn("[IframeTransport] Not inside an iframe");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
win.parent.postMessage(message, this.targetOrigin);
|
|
130
|
+
}
|
|
131
|
+
subscribe(listener) {
|
|
132
|
+
const win = this.getWindow();
|
|
133
|
+
if (!win) {
|
|
134
|
+
return () => {
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const handler = (event) => {
|
|
138
|
+
if (typeof event.data === "string") {
|
|
139
|
+
listener(event.data);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
win.addEventListener("message", handler);
|
|
143
|
+
return () => win.removeEventListener("message", handler);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var iframeDetector = {
|
|
147
|
+
name: "iframe",
|
|
148
|
+
priority: 80,
|
|
149
|
+
// Lowest priority - fallback
|
|
150
|
+
detect: () => {
|
|
151
|
+
return typeof window !== "undefined" && window.parent !== window;
|
|
152
|
+
},
|
|
153
|
+
createTransport: () => new IframeTransport()
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// src/transports/WindowTransport.ts
|
|
157
|
+
var WindowTransport = class extends BaseTransport {
|
|
158
|
+
/**
|
|
159
|
+
* Create a window transport
|
|
160
|
+
* @param targetOrigin Origin to send messages to (default: '*')
|
|
161
|
+
*/
|
|
162
|
+
constructor(targetOrigin = "*") {
|
|
163
|
+
super();
|
|
164
|
+
this.name = "window";
|
|
165
|
+
this.targetOrigin = targetOrigin;
|
|
166
|
+
}
|
|
167
|
+
isAvailable() {
|
|
168
|
+
const win = this.getWindow();
|
|
169
|
+
if (!win) return false;
|
|
170
|
+
return win.opener !== null && !win.opener.closed;
|
|
171
|
+
}
|
|
172
|
+
send(message) {
|
|
173
|
+
const win = this.getWindow();
|
|
174
|
+
if (!win) {
|
|
175
|
+
console.warn("[WindowTransport] Window is not available");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!win.opener || win.opener.closed) {
|
|
179
|
+
console.warn("[WindowTransport] Opener window is not available");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
win.opener.postMessage(message, this.targetOrigin);
|
|
183
|
+
}
|
|
184
|
+
subscribe(listener) {
|
|
185
|
+
const win = this.getWindow();
|
|
186
|
+
if (!win) {
|
|
187
|
+
return () => {
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const handler = (event) => {
|
|
191
|
+
if (typeof event.data === "string") {
|
|
192
|
+
listener(event.data);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
win.addEventListener("message", handler);
|
|
196
|
+
return () => win.removeEventListener("message", handler);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
var windowDetector = {
|
|
200
|
+
name: "window",
|
|
201
|
+
priority: 70,
|
|
202
|
+
// Below iframe (80), above postmessage (10)
|
|
203
|
+
detect: () => {
|
|
204
|
+
try {
|
|
205
|
+
return typeof window !== "undefined" && window.opener != null && !window.opener.closed;
|
|
206
|
+
} catch {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
createTransport: () => new WindowTransport()
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// src/transports/PostMessageTransport.ts
|
|
214
|
+
var PostMessageTransport = class extends BaseTransport {
|
|
215
|
+
constructor() {
|
|
216
|
+
super(...arguments);
|
|
217
|
+
this.name = "postmessage";
|
|
218
|
+
}
|
|
219
|
+
isAvailable() {
|
|
220
|
+
return typeof this.getWindow()?.addEventListener === "function";
|
|
221
|
+
}
|
|
222
|
+
send(message) {
|
|
223
|
+
const win = this.getWindow();
|
|
224
|
+
if (!win) return;
|
|
225
|
+
win.postMessage(message, "*");
|
|
226
|
+
}
|
|
227
|
+
subscribe(listener) {
|
|
228
|
+
const win = this.getWindow();
|
|
229
|
+
if (!win) {
|
|
230
|
+
return () => {
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const handler = (event) => {
|
|
234
|
+
if (typeof event.data === "string") {
|
|
235
|
+
listener(event.data);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
win.addEventListener("message", handler);
|
|
239
|
+
return () => win.removeEventListener("message", handler);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var postMessageDetector = {
|
|
243
|
+
name: "postmessage",
|
|
244
|
+
priority: 10,
|
|
245
|
+
// Lowest priority — fallback for any browser environment
|
|
246
|
+
detect: () => {
|
|
247
|
+
return typeof window !== "undefined" && typeof window.addEventListener === "function";
|
|
248
|
+
},
|
|
249
|
+
createTransport: () => new PostMessageTransport()
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/transports/NullTransport.ts
|
|
253
|
+
var NullTransport = class extends BaseTransport {
|
|
254
|
+
constructor() {
|
|
255
|
+
super(...arguments);
|
|
256
|
+
this.name = "null";
|
|
257
|
+
}
|
|
258
|
+
isAvailable() {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
send(_message) {
|
|
262
|
+
if (process.env.NODE_ENV === "development") {
|
|
263
|
+
console.warn("[NullTransport] No transport available, message not sent");
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
subscribe(_listener) {
|
|
267
|
+
return () => {
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// src/TransportRegistry.ts
|
|
273
|
+
var TransportRegistryClass = class {
|
|
274
|
+
constructor() {
|
|
275
|
+
this.detectors = [];
|
|
276
|
+
this.cachedTransport = null;
|
|
277
|
+
this.register(cefSharpDetector);
|
|
278
|
+
this.register(reactNativeDetector);
|
|
279
|
+
this.register(iframeDetector);
|
|
280
|
+
this.register(windowDetector);
|
|
281
|
+
this.register(postMessageDetector);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Register a custom transport detector
|
|
285
|
+
* @param detector The detector to register
|
|
286
|
+
*/
|
|
287
|
+
register(detector) {
|
|
288
|
+
this.detectors = this.detectors.filter((d) => d.name !== detector.name);
|
|
289
|
+
this.detectors.push(detector);
|
|
290
|
+
this.detectors.sort((a, b) => b.priority - a.priority);
|
|
291
|
+
this.cachedTransport = null;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Unregister a transport detector by name
|
|
295
|
+
* @param name Name of the detector to remove
|
|
296
|
+
*/
|
|
297
|
+
unregister(name) {
|
|
298
|
+
this.detectors = this.detectors.filter((d) => d.name !== name);
|
|
299
|
+
this.cachedTransport = null;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get all registered detectors
|
|
303
|
+
*/
|
|
304
|
+
getDetectors() {
|
|
305
|
+
return this.detectors;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Detect and return the appropriate transport for the current environment
|
|
309
|
+
* Results are cached for performance
|
|
310
|
+
* @param forceRedetect Force re-detection (ignores cache)
|
|
311
|
+
*/
|
|
312
|
+
detect(forceRedetect = false) {
|
|
313
|
+
if (this.cachedTransport && !forceRedetect) {
|
|
314
|
+
return this.cachedTransport;
|
|
315
|
+
}
|
|
316
|
+
for (const detector of this.detectors) {
|
|
317
|
+
try {
|
|
318
|
+
if (detector.detect()) {
|
|
319
|
+
this.cachedTransport = detector.createTransport();
|
|
320
|
+
return this.cachedTransport;
|
|
321
|
+
}
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.warn(`[TransportRegistry] Detector "${detector.name}" threw an error:`, error);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
this.cachedTransport = new NullTransport();
|
|
327
|
+
return this.cachedTransport;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Clear the cached transport (useful for testing)
|
|
331
|
+
*/
|
|
332
|
+
clearCache() {
|
|
333
|
+
this.cachedTransport = null;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Reset registry to default state (built-in detectors only)
|
|
337
|
+
*/
|
|
338
|
+
reset() {
|
|
339
|
+
this.detectors = [];
|
|
340
|
+
this.cachedTransport = null;
|
|
341
|
+
this.register(cefSharpDetector);
|
|
342
|
+
this.register(reactNativeDetector);
|
|
343
|
+
this.register(iframeDetector);
|
|
344
|
+
this.register(windowDetector);
|
|
345
|
+
this.register(postMessageDetector);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var TransportRegistry = new TransportRegistryClass();
|
|
349
|
+
var detectTransport = (forceRedetect = false) => {
|
|
350
|
+
return TransportRegistry.detect(forceRedetect);
|
|
351
|
+
};
|
|
352
|
+
var registerTransport = (detector) => {
|
|
353
|
+
TransportRegistry.register(detector);
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
export { BaseTransport, CefSharpTransport, IframeTransport, NullTransport, PostMessageTransport, ReactNativeTransport, TransportRegistry, WindowTransport, cefSharpDetector, detectTransport, iframeDetector, postMessageDetector, reactNativeDetector, registerTransport, windowDetector };
|
|
357
|
+
//# sourceMappingURL=index.mjs.map
|
|
358
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/BaseTransport.ts","../src/transports/CefSharpTransport.ts","../src/transports/ReactNativeTransport.ts","../src/transports/IframeTransport.ts","../src/transports/WindowTransport.ts","../src/transports/PostMessageTransport.ts","../src/transports/NullTransport.ts","../src/TransportRegistry.ts"],"names":[],"mappings":"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","file":"index.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';\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","import { BaseTransport } from '../BaseTransport';\r\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\r\n\r\ndeclare global {\r\n interface Window {\r\n ReactNativeWebView?: {\r\n postMessage: (message: string) => void;\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transport for React Native WebView\r\n * Used when web content is displayed inside a React Native app\r\n *\r\n * @example\r\n * ```typescript\r\n * import { ReactNativeTransport } from '@aspectly/transports/react-native';\r\n *\r\n * const transport = new ReactNativeTransport();\r\n * if (transport.isAvailable()) {\r\n * transport.send(JSON.stringify({ type: 'hello' }));\r\n * }\r\n * ```\r\n */\r\nexport class ReactNativeTransport extends BaseTransport {\r\n readonly name = 'react-native';\r\n\r\n isAvailable(): boolean {\r\n const win = this.getWindow();\r\n return typeof win?.ReactNativeWebView?.postMessage === 'function';\r\n }\r\n\r\n send(message: string): void {\r\n const win = this.getWindow();\r\n if (!win?.ReactNativeWebView?.postMessage) {\r\n console.warn('[ReactNativeTransport] ReactNativeWebView.postMessage is not available');\r\n return;\r\n }\r\n // React Native WebView expects message wrapped in quotes (iOS quirk)\r\n win.ReactNativeWebView.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 // React Native 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 reactNativeDetector: TransportDetector = {\r\n name: 'react-native',\r\n priority: 90, // Second priority\r\n detect: () => {\r\n return typeof window !== 'undefined' &&\r\n typeof window.ReactNativeWebView?.postMessage === 'function';\r\n },\r\n createTransport: () => new ReactNativeTransport(),\r\n};\r\n","import { BaseTransport } from '../BaseTransport';\r\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\r\n\r\n/**\r\n * Transport for iframe/window.postMessage communication\r\n * Used when web content is displayed inside an iframe\r\n *\r\n * @example\r\n * ```typescript\r\n * import { IframeTransport } from '@aspectly/transports/iframe';\r\n *\r\n * const transport = new IframeTransport();\r\n * if (transport.isAvailable()) {\r\n * transport.send(JSON.stringify({ type: 'hello' }));\r\n * }\r\n * ```\r\n */\r\nexport class IframeTransport extends BaseTransport {\r\n readonly name = 'iframe';\r\n private readonly targetOrigin: string;\r\n\r\n /**\r\n * Create an iframe transport\r\n * @param targetOrigin Origin to send messages to (default: '*')\r\n */\r\n constructor(targetOrigin: string = '*') {\r\n super();\r\n this.targetOrigin = targetOrigin;\r\n }\r\n\r\n isAvailable(): boolean {\r\n const win = this.getWindow();\r\n if (!win) return false;\r\n // Check if we're inside an iframe (parent !== self)\r\n return win.parent !== win;\r\n }\r\n\r\n send(message: string): void {\r\n const win = this.getWindow();\r\n if (!win) {\r\n console.warn('[IframeTransport] Window is not available');\r\n return;\r\n }\r\n if (win.parent === win) {\r\n console.warn('[IframeTransport] Not inside an iframe');\r\n return;\r\n }\r\n win.parent.postMessage(message, this.targetOrigin);\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 const handler = (event: MessageEvent): void => {\r\n // Optionally filter by origin here if targetOrigin !== '*'\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 iframeDetector: TransportDetector = {\r\n name: 'iframe',\r\n priority: 80, // Lowest priority - fallback\r\n detect: () => {\r\n return typeof window !== 'undefined' && window.parent !== window;\r\n },\r\n createTransport: () => new IframeTransport(),\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","import { BaseTransport } from '../BaseTransport';\r\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\r\n\r\n/**\r\n * Fallback transport for browser environments.\r\n * Listens for window.postMessage events, allowing parent windows\r\n * to receive messages from child iframes.\r\n */\r\nexport class PostMessageTransport extends BaseTransport {\r\n readonly name = 'postmessage';\r\n\r\n isAvailable(): boolean {\r\n return typeof this.getWindow()?.addEventListener === 'function';\r\n }\r\n\r\n send(message: string): void {\r\n const win = this.getWindow();\r\n if (!win) return;\r\n win.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 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 postMessageDetector: TransportDetector = {\r\n name: 'postmessage',\r\n priority: 10, // Lowest priority — fallback for any browser environment\r\n detect: () => {\r\n return typeof window !== 'undefined' &&\r\n typeof window.addEventListener === 'function';\r\n },\r\n createTransport: () => new PostMessageTransport(),\r\n};\r\n","import { BaseTransport } from '../BaseTransport';\r\nimport type { TransportListener, TransportUnsubscribe } from '../types';\r\n\r\n/**\r\n * Null transport - used when no transport is available\r\n * All operations are no-ops. Useful for SSR or testing.\r\n */\r\nexport class NullTransport extends BaseTransport {\r\n readonly name = 'null';\r\n\r\n isAvailable(): boolean {\r\n // Always \"available\" as a fallback, but does nothing\r\n return true;\r\n }\r\n\r\n send(_message: string): void {\r\n // No-op\r\n if (process.env.NODE_ENV === 'development') {\r\n console.warn('[NullTransport] No transport available, message not sent');\r\n }\r\n }\r\n\r\n subscribe(_listener: TransportListener): TransportUnsubscribe {\r\n // No-op\r\n return () => {};\r\n }\r\n}\r\n","import type { Transport, TransportDetector } from './types';\r\nimport { cefSharpDetector } from './transports/CefSharpTransport';\r\nimport { reactNativeDetector } from './transports/ReactNativeTransport';\r\nimport { iframeDetector } from './transports/IframeTransport';\r\nimport { windowDetector } from './transports/WindowTransport';\r\nimport { postMessageDetector } from './transports/PostMessageTransport';\r\nimport { NullTransport } from './transports/NullTransport';\r\n\r\n/**\r\n * Registry for transport detectors\r\n * Manages auto-detection of the current environment\r\n */\r\nclass TransportRegistryClass {\r\n private detectors: TransportDetector[] = [];\r\n private cachedTransport: Transport | null = null;\r\n\r\n constructor() {\r\n // Register built-in detectors\r\n this.register(cefSharpDetector);\r\n this.register(reactNativeDetector);\r\n this.register(iframeDetector);\r\n this.register(windowDetector);\r\n this.register(postMessageDetector);\r\n }\r\n\r\n /**\r\n * Register a custom transport detector\r\n * @param detector The detector to register\r\n */\r\n register(detector: TransportDetector): void {\r\n // Remove existing detector with same name\r\n this.detectors = this.detectors.filter(d => d.name !== detector.name);\r\n this.detectors.push(detector);\r\n // Sort by priority (descending)\r\n this.detectors.sort((a, b) => b.priority - a.priority);\r\n // Clear cache when detectors change\r\n this.cachedTransport = null;\r\n }\r\n\r\n /**\r\n * Unregister a transport detector by name\r\n * @param name Name of the detector to remove\r\n */\r\n unregister(name: string): void {\r\n this.detectors = this.detectors.filter(d => d.name !== name);\r\n this.cachedTransport = null;\r\n }\r\n\r\n /**\r\n * Get all registered detectors\r\n */\r\n getDetectors(): readonly TransportDetector[] {\r\n return this.detectors;\r\n }\r\n\r\n /**\r\n * Detect and return the appropriate transport for the current environment\r\n * Results are cached for performance\r\n * @param forceRedetect Force re-detection (ignores cache)\r\n */\r\n detect(forceRedetect = false): Transport {\r\n if (this.cachedTransport && !forceRedetect) {\r\n return this.cachedTransport;\r\n }\r\n\r\n for (const detector of this.detectors) {\r\n try {\r\n if (detector.detect()) {\r\n this.cachedTransport = detector.createTransport();\r\n return this.cachedTransport;\r\n }\r\n } catch (error) {\r\n console.warn(`[TransportRegistry] Detector \"${detector.name}\" threw an error:`, error);\r\n }\r\n }\r\n\r\n // No transport detected, return NullTransport\r\n this.cachedTransport = new NullTransport();\r\n return this.cachedTransport;\r\n }\r\n\r\n /**\r\n * Clear the cached transport (useful for testing)\r\n */\r\n clearCache(): void {\r\n this.cachedTransport = null;\r\n }\r\n\r\n /**\r\n * Reset registry to default state (built-in detectors only)\r\n */\r\n reset(): void {\r\n this.detectors = [];\r\n this.cachedTransport = null;\r\n this.register(cefSharpDetector);\r\n this.register(reactNativeDetector);\r\n this.register(iframeDetector);\r\n this.register(windowDetector);\r\n this.register(postMessageDetector);\r\n }\r\n}\r\n\r\n/**\r\n * Global transport registry instance\r\n */\r\nexport const TransportRegistry = new TransportRegistryClass();\r\n\r\n/**\r\n * Convenience function to detect transport\r\n */\r\nexport const detectTransport = (forceRedetect = false): Transport => {\r\n return TransportRegistry.detect(forceRedetect);\r\n};\r\n\r\n/**\r\n * Convenience function to register a custom detector\r\n */\r\nexport const registerTransport = (detector: TransportDetector): void => {\r\n TransportRegistry.register(detector);\r\n};\r\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
ReactNativeWebView?: {
|
|
7
|
+
postMessage: (message: string) => void;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Transport for React Native WebView
|
|
13
|
+
* Used when web content is displayed inside a React Native app
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { ReactNativeTransport } from '@aspectly/transports/react-native';
|
|
18
|
+
*
|
|
19
|
+
* const transport = new ReactNativeTransport();
|
|
20
|
+
* if (transport.isAvailable()) {
|
|
21
|
+
* transport.send(JSON.stringify({ type: 'hello' }));
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare class ReactNativeTransport extends BaseTransport {
|
|
26
|
+
readonly name = "react-native";
|
|
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 reactNativeDetector: TransportDetector;
|
|
35
|
+
|
|
36
|
+
export { ReactNativeTransport, TransportListener, TransportUnsubscribe, reactNativeDetector };
|
|
@@ -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
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
ReactNativeWebView?: {
|
|
7
|
+
postMessage: (message: string) => void;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Transport for React Native WebView
|
|
13
|
+
* Used when web content is displayed inside a React Native app
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { ReactNativeTransport } from '@aspectly/transports/react-native';
|
|
18
|
+
*
|
|
19
|
+
* const transport = new ReactNativeTransport();
|
|
20
|
+
* if (transport.isAvailable()) {
|
|
21
|
+
* transport.send(JSON.stringify({ type: 'hello' }));
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare class ReactNativeTransport extends BaseTransport {
|
|
26
|
+
readonly name = "react-native";
|
|
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 reactNativeDetector: TransportDetector;
|
|
35
|
+
|
|
36
|
+
export { ReactNativeTransport, TransportListener, TransportUnsubscribe, reactNativeDetector };
|
|
@@ -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/ReactNativeTransport.ts
|
|
20
|
+
var ReactNativeTransport = class extends BaseTransport {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(...arguments);
|
|
23
|
+
this.name = "react-native";
|
|
24
|
+
}
|
|
25
|
+
isAvailable() {
|
|
26
|
+
const win = this.getWindow();
|
|
27
|
+
return typeof win?.ReactNativeWebView?.postMessage === "function";
|
|
28
|
+
}
|
|
29
|
+
send(message) {
|
|
30
|
+
const win = this.getWindow();
|
|
31
|
+
if (!win?.ReactNativeWebView?.postMessage) {
|
|
32
|
+
console.warn("[ReactNativeTransport] ReactNativeWebView.postMessage is not available");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
win.ReactNativeWebView.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 reactNativeDetector = {
|
|
53
|
+
name: "react-native",
|
|
54
|
+
priority: 90,
|
|
55
|
+
// Second priority
|
|
56
|
+
detect: () => {
|
|
57
|
+
return typeof window !== "undefined" && typeof window.ReactNativeWebView?.postMessage === "function";
|
|
58
|
+
},
|
|
59
|
+
createTransport: () => new ReactNativeTransport()
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
exports.ReactNativeTransport = ReactNativeTransport;
|
|
63
|
+
exports.reactNativeDetector = reactNativeDetector;
|
|
64
|
+
//# sourceMappingURL=react-native.js.map
|
|
65
|
+
//# sourceMappingURL=react-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/BaseTransport.ts","../src/transports/ReactNativeTransport.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;;;ACDO,IAAM,oBAAA,GAAN,cAAmC,aAAA,CAAc;AAAA,EAAjD,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AACL,IAAA,IAAA,CAAS,IAAA,GAAO,cAAA;AAAA,EAAA;AAAA,EAEhB,WAAA,GAAuB;AACrB,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,OAAO,OAAO,GAAA,EAAK,kBAAA,EAAoB,WAAA,KAAgB,UAAA;AAAA,EACzD;AAAA,EAEA,KAAK,OAAA,EAAuB;AAC1B,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK,kBAAA,EAAoB,WAAA,EAAa;AACzC,MAAA,OAAA,CAAQ,KAAK,wEAAwE,CAAA;AACrF,MAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,kBAAA,CAAmB,WAAA,CAAY,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,CAAG,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;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,mBAAA,GAAyC;AAAA,EACpD,IAAA,EAAM,cAAA;AAAA,EACN,QAAA,EAAU,EAAA;AAAA;AAAA,EACV,QAAQ,MAAM;AACZ,IAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,MAAA,CAAO,oBAAoB,WAAA,KAAgB,UAAA;AAAA,EAC3D,CAAA;AAAA,EACA,eAAA,EAAiB,MAAM,IAAI,oBAAA;AAC7B","file":"react-native.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 ReactNativeWebView?: {\r\n postMessage: (message: string) => void;\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transport for React Native WebView\r\n * Used when web content is displayed inside a React Native app\r\n *\r\n * @example\r\n * ```typescript\r\n * import { ReactNativeTransport } from '@aspectly/transports/react-native';\r\n *\r\n * const transport = new ReactNativeTransport();\r\n * if (transport.isAvailable()) {\r\n * transport.send(JSON.stringify({ type: 'hello' }));\r\n * }\r\n * ```\r\n */\r\nexport class ReactNativeTransport extends BaseTransport {\r\n readonly name = 'react-native';\r\n\r\n isAvailable(): boolean {\r\n const win = this.getWindow();\r\n return typeof win?.ReactNativeWebView?.postMessage === 'function';\r\n }\r\n\r\n send(message: string): void {\r\n const win = this.getWindow();\r\n if (!win?.ReactNativeWebView?.postMessage) {\r\n console.warn('[ReactNativeTransport] ReactNativeWebView.postMessage is not available');\r\n return;\r\n }\r\n // React Native WebView expects message wrapped in quotes (iOS quirk)\r\n win.ReactNativeWebView.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 // React Native 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 reactNativeDetector: TransportDetector = {\r\n name: 'react-native',\r\n priority: 90, // Second priority\r\n detect: () => {\r\n return typeof window !== 'undefined' &&\r\n typeof window.ReactNativeWebView?.postMessage === 'function';\r\n },\r\n createTransport: () => new ReactNativeTransport(),\r\n};\r\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
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/ReactNativeTransport.ts
|
|
18
|
+
var ReactNativeTransport = class extends BaseTransport {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.name = "react-native";
|
|
22
|
+
}
|
|
23
|
+
isAvailable() {
|
|
24
|
+
const win = this.getWindow();
|
|
25
|
+
return typeof win?.ReactNativeWebView?.postMessage === "function";
|
|
26
|
+
}
|
|
27
|
+
send(message) {
|
|
28
|
+
const win = this.getWindow();
|
|
29
|
+
if (!win?.ReactNativeWebView?.postMessage) {
|
|
30
|
+
console.warn("[ReactNativeTransport] ReactNativeWebView.postMessage is not available");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
win.ReactNativeWebView.postMessage(`'${message}'`);
|
|
34
|
+
}
|
|
35
|
+
subscribe(listener) {
|
|
36
|
+
const win = this.getWindow();
|
|
37
|
+
if (!win) {
|
|
38
|
+
return () => {
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const handler = (event) => {
|
|
42
|
+
if (typeof event.data === "string") {
|
|
43
|
+
listener(event.data);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
win.addEventListener("message", handler);
|
|
47
|
+
return () => win.removeEventListener("message", handler);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var reactNativeDetector = {
|
|
51
|
+
name: "react-native",
|
|
52
|
+
priority: 90,
|
|
53
|
+
// Second priority
|
|
54
|
+
detect: () => {
|
|
55
|
+
return typeof window !== "undefined" && typeof window.ReactNativeWebView?.postMessage === "function";
|
|
56
|
+
},
|
|
57
|
+
createTransport: () => new ReactNativeTransport()
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export { ReactNativeTransport, reactNativeDetector };
|
|
61
|
+
//# sourceMappingURL=react-native.mjs.map
|
|
62
|
+
//# sourceMappingURL=react-native.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/BaseTransport.ts","../src/transports/ReactNativeTransport.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;;;ACDO,IAAM,oBAAA,GAAN,cAAmC,aAAA,CAAc;AAAA,EAAjD,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AACL,IAAA,IAAA,CAAS,IAAA,GAAO,cAAA;AAAA,EAAA;AAAA,EAEhB,WAAA,GAAuB;AACrB,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,OAAO,OAAO,GAAA,EAAK,kBAAA,EAAoB,WAAA,KAAgB,UAAA;AAAA,EACzD;AAAA,EAEA,KAAK,OAAA,EAAuB;AAC1B,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,EAAU;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK,kBAAA,EAAoB,WAAA,EAAa;AACzC,MAAA,OAAA,CAAQ,KAAK,wEAAwE,CAAA;AACrF,MAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,kBAAA,CAAmB,WAAA,CAAY,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,CAAG,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;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,mBAAA,GAAyC;AAAA,EACpD,IAAA,EAAM,cAAA;AAAA,EACN,QAAA,EAAU,EAAA;AAAA;AAAA,EACV,QAAQ,MAAM;AACZ,IAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,MAAA,CAAO,oBAAoB,WAAA,KAAgB,UAAA;AAAA,EAC3D,CAAA;AAAA,EACA,eAAA,EAAiB,MAAM,IAAI,oBAAA;AAC7B","file":"react-native.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';\r\nimport type { TransportListener, TransportUnsubscribe, TransportDetector } from '../types';\r\n\r\ndeclare global {\r\n interface Window {\r\n ReactNativeWebView?: {\r\n postMessage: (message: string) => void;\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transport for React Native WebView\r\n * Used when web content is displayed inside a React Native app\r\n *\r\n * @example\r\n * ```typescript\r\n * import { ReactNativeTransport } from '@aspectly/transports/react-native';\r\n *\r\n * const transport = new ReactNativeTransport();\r\n * if (transport.isAvailable()) {\r\n * transport.send(JSON.stringify({ type: 'hello' }));\r\n * }\r\n * ```\r\n */\r\nexport class ReactNativeTransport extends BaseTransport {\r\n readonly name = 'react-native';\r\n\r\n isAvailable(): boolean {\r\n const win = this.getWindow();\r\n return typeof win?.ReactNativeWebView?.postMessage === 'function';\r\n }\r\n\r\n send(message: string): void {\r\n const win = this.getWindow();\r\n if (!win?.ReactNativeWebView?.postMessage) {\r\n console.warn('[ReactNativeTransport] ReactNativeWebView.postMessage is not available');\r\n return;\r\n }\r\n // React Native WebView expects message wrapped in quotes (iOS quirk)\r\n win.ReactNativeWebView.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 // React Native 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 reactNativeDetector: TransportDetector = {\r\n name: 'react-native',\r\n priority: 90, // Second priority\r\n detect: () => {\r\n return typeof window !== 'undefined' &&\r\n typeof window.ReactNativeWebView?.postMessage === 'function';\r\n },\r\n createTransport: () => new ReactNativeTransport(),\r\n};\r\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
/**
|
|
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 };
|