@aspectly/core 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 +188 -0
- package/dist/AspectlyBridge-hGuDjcI6.d.mts +242 -0
- package/dist/AspectlyBridge-hGuDjcI6.d.ts +242 -0
- package/dist/browser.d.mts +24 -0
- package/dist/browser.d.ts +24 -0
- package/dist/browser.js +398 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.mjs +396 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/index.d.mts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +420 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +412 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +71 -0
- package/src/AspectlyBridge.test.ts +78 -0
- package/src/AspectlyBridge.ts +44 -0
- package/src/BridgeBase.test.ts +132 -0
- package/src/BridgeBase.ts +63 -0
- package/src/BridgeCore.test.ts +254 -0
- package/src/BridgeCore.ts +138 -0
- package/src/BridgeInternal.test.ts +403 -0
- package/src/BridgeInternal.ts +305 -0
- package/src/browser.ts +27 -0
- package/src/index.ts +28 -0
- package/src/types.ts +134 -0
package/dist/browser.mjs
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
// src/BridgeCore.ts
|
|
2
|
+
var _BridgeCore = class _BridgeCore {
|
|
3
|
+
};
|
|
4
|
+
_BridgeCore.BRIDGE_EVENT_TYPE = "BridgeEvent";
|
|
5
|
+
_BridgeCore.isJSONObject = (str) => {
|
|
6
|
+
return str.startsWith("{") && str.endsWith("}");
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Wraps an event in the bridge protocol format
|
|
10
|
+
*/
|
|
11
|
+
_BridgeCore.wrapBridgeEvent = (event) => {
|
|
12
|
+
return JSON.stringify({
|
|
13
|
+
event,
|
|
14
|
+
type: _BridgeCore.BRIDGE_EVENT_TYPE
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Creates a listener wrapper that parses incoming messages
|
|
19
|
+
*/
|
|
20
|
+
_BridgeCore.wrapListener = (listener) => (data) => {
|
|
21
|
+
if (typeof data !== "string") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!data) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let processedData = data;
|
|
28
|
+
if (processedData.startsWith("'") && processedData.endsWith("'")) {
|
|
29
|
+
processedData = processedData.substring(1, processedData.length - 1);
|
|
30
|
+
}
|
|
31
|
+
if (!_BridgeCore.isJSONObject(processedData)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const eventData = JSON.parse(processedData);
|
|
36
|
+
if (!eventData || eventData.type !== _BridgeCore.BRIDGE_EVENT_TYPE) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
listener(eventData.event);
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Creates a browser-specific message event listener
|
|
45
|
+
*/
|
|
46
|
+
_BridgeCore.browserListener = (listener) => {
|
|
47
|
+
const triggerEvent = _BridgeCore.wrapListener(listener);
|
|
48
|
+
return (originalEvent) => {
|
|
49
|
+
if (!originalEvent?.data) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
triggerEvent(originalEvent.data);
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Creates a React Native WebView message listener
|
|
57
|
+
*/
|
|
58
|
+
_BridgeCore.webViewListener = (listener) => {
|
|
59
|
+
const triggerEvent = _BridgeCore.wrapListener(listener);
|
|
60
|
+
return (originalEvent) => {
|
|
61
|
+
if (!originalEvent?.nativeEvent?.data) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
triggerEvent(originalEvent.nativeEvent.data);
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Sends an event to the parent context (WebView or iframe parent)
|
|
69
|
+
*/
|
|
70
|
+
_BridgeCore.sendEvent = (event) => {
|
|
71
|
+
const bridgeEvent = _BridgeCore.wrapBridgeEvent(event);
|
|
72
|
+
if (typeof window === "undefined") {
|
|
73
|
+
console.warn("Window is undefined");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const RNW = window.ReactNativeWebView;
|
|
77
|
+
if (typeof RNW?.postMessage === "function") {
|
|
78
|
+
RNW.postMessage(`'${bridgeEvent}'`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (window.parent === window) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
window.parent.postMessage(bridgeEvent, "*");
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Subscribes to window message events
|
|
88
|
+
* @returns Cleanup function to unsubscribe
|
|
89
|
+
*/
|
|
90
|
+
_BridgeCore.subscribe = (listener) => {
|
|
91
|
+
const browserListener = _BridgeCore.browserListener(listener);
|
|
92
|
+
if (typeof window === "undefined" || !window.addEventListener) {
|
|
93
|
+
return () => {
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
window.addEventListener("message", browserListener);
|
|
97
|
+
return () => window.removeEventListener("message", browserListener);
|
|
98
|
+
};
|
|
99
|
+
var BridgeCore = _BridgeCore;
|
|
100
|
+
|
|
101
|
+
// src/BridgeInternal.ts
|
|
102
|
+
var internalEvent = (type, data) => ({
|
|
103
|
+
type,
|
|
104
|
+
data
|
|
105
|
+
});
|
|
106
|
+
var internalResultEvent = (data) => internalEvent("Result" /* Result */, data);
|
|
107
|
+
var DEFAULT_TIMEOUT = 1e5;
|
|
108
|
+
var BridgeInternal = class {
|
|
109
|
+
constructor(sendEvent, options) {
|
|
110
|
+
this.requests = [];
|
|
111
|
+
this.handlers = {};
|
|
112
|
+
this.available = false;
|
|
113
|
+
this.supportedMethods = [];
|
|
114
|
+
this.listeners = [];
|
|
115
|
+
/**
|
|
116
|
+
* Subscribe to all result events
|
|
117
|
+
*/
|
|
118
|
+
this.subscribe = (listener) => {
|
|
119
|
+
return this.listeners.push(listener);
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Unsubscribe from result events
|
|
123
|
+
*/
|
|
124
|
+
this.unsubscribe = (listener) => {
|
|
125
|
+
this.listeners = this.listeners.filter(
|
|
126
|
+
(oldListener) => oldListener !== listener
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
this.checkDiff = (a, b) => {
|
|
130
|
+
return a.filter((x) => !b.includes(x)).length > 0 || b.filter((x) => !a.includes(x)).length > 0;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Initialize the bridge with handlers
|
|
134
|
+
* @param handlers Map of method names to handler functions
|
|
135
|
+
* @returns Promise that resolves when the other side acknowledges
|
|
136
|
+
*/
|
|
137
|
+
this.init = (handlers = {}) => {
|
|
138
|
+
const oldMethods = Object.keys(this.handlers);
|
|
139
|
+
const newMethods = Object.keys(handlers);
|
|
140
|
+
this.handlers = handlers;
|
|
141
|
+
if (!this.checkDiff(oldMethods, newMethods)) {
|
|
142
|
+
return Promise.resolve(true);
|
|
143
|
+
}
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
145
|
+
this.initPromise = { resolve, reject };
|
|
146
|
+
this.sendEvent(
|
|
147
|
+
internalEvent("Init" /* Init */, {
|
|
148
|
+
methods: newMethods
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Handle incoming bridge events
|
|
155
|
+
*/
|
|
156
|
+
this.handleCoreEvent = (event) => {
|
|
157
|
+
const { type, data } = event;
|
|
158
|
+
switch (type) {
|
|
159
|
+
case "Init" /* Init */:
|
|
160
|
+
this.handleInit(data);
|
|
161
|
+
break;
|
|
162
|
+
case "InitResult" /* InitResult */:
|
|
163
|
+
this.handleInitResult(data);
|
|
164
|
+
break;
|
|
165
|
+
case "Request" /* Request */:
|
|
166
|
+
this.handleRequest(data);
|
|
167
|
+
break;
|
|
168
|
+
case "Result" /* Result */:
|
|
169
|
+
this.handleResult(data);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Handle incoming requests and execute the appropriate handler
|
|
175
|
+
*/
|
|
176
|
+
this.handleRequest = (request) => {
|
|
177
|
+
const { method, params, request_id } = request;
|
|
178
|
+
new Promise((resolve, reject) => {
|
|
179
|
+
let timeout = false;
|
|
180
|
+
if (!Object.prototype.hasOwnProperty.call(this.handlers, method)) {
|
|
181
|
+
reject({
|
|
182
|
+
error_type: "UNSUPPORTED_METHOD" /* UNSUPPORTED_METHOD */,
|
|
183
|
+
error: new Error(`Handler for \xAB${method}\xBB is not registered`)
|
|
184
|
+
});
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const timer = setTimeout(() => {
|
|
188
|
+
timeout = true;
|
|
189
|
+
reject({
|
|
190
|
+
error_type: "METHOD_EXECUTION_TIMEOUT" /* METHOD_EXECUTION_TIMEOUT */,
|
|
191
|
+
error: new Error("Execution timeout exceeded")
|
|
192
|
+
});
|
|
193
|
+
}, this.timeout);
|
|
194
|
+
const handler = this.handlers[method];
|
|
195
|
+
if (!handler) {
|
|
196
|
+
reject({
|
|
197
|
+
error_type: "UNSUPPORTED_METHOD" /* UNSUPPORTED_METHOD */,
|
|
198
|
+
error: new Error(`Handler for \xAB${method}\xBB is undefined`)
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
handler(params).then((result) => {
|
|
203
|
+
if (timeout) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
resolve(result);
|
|
208
|
+
}).catch((error) => {
|
|
209
|
+
if (timeout) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
clearTimeout(timer);
|
|
213
|
+
reject({
|
|
214
|
+
error_type: "REJECTED" /* REJECTED */,
|
|
215
|
+
error
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
}).then((data) => {
|
|
219
|
+
this.sendEvent(
|
|
220
|
+
internalResultEvent({
|
|
221
|
+
type: "Success" /* Success */,
|
|
222
|
+
data,
|
|
223
|
+
method,
|
|
224
|
+
request_id
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
}).catch(
|
|
228
|
+
({
|
|
229
|
+
error_type,
|
|
230
|
+
error
|
|
231
|
+
}) => {
|
|
232
|
+
this.sendEvent(
|
|
233
|
+
internalResultEvent({
|
|
234
|
+
type: "Error" /* Error */,
|
|
235
|
+
request_id,
|
|
236
|
+
method,
|
|
237
|
+
data: {
|
|
238
|
+
error_message: error.message,
|
|
239
|
+
error_type
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
this.handleResult = (result) => {
|
|
247
|
+
this.handleRequestResult(result);
|
|
248
|
+
this.listeners.forEach((listener) => listener(result));
|
|
249
|
+
};
|
|
250
|
+
this.handleRequestResult = (result) => {
|
|
251
|
+
if (!result || !Object.prototype.hasOwnProperty.call(result, "request_id")) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (!Object.prototype.hasOwnProperty.call(result, "type")) {
|
|
255
|
+
console.warn("unknown result", result);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const { request_id, data, type } = result;
|
|
259
|
+
const request = this.requests[Number(request_id)];
|
|
260
|
+
if (!request) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (type === "Success" /* Success */) {
|
|
264
|
+
request.resolve(data);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (type === "Error" /* Error */) {
|
|
268
|
+
request.reject(data);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
this.handleInit = (data) => {
|
|
272
|
+
this.available = true;
|
|
273
|
+
this.supportedMethods = data.methods;
|
|
274
|
+
this.sendEvent(internalEvent("InitResult" /* InitResult */, true));
|
|
275
|
+
};
|
|
276
|
+
this.handleInitResult = (success) => {
|
|
277
|
+
if (success) {
|
|
278
|
+
this.initPromise?.resolve(true);
|
|
279
|
+
} else {
|
|
280
|
+
this.initPromise?.reject();
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Send a request to the other side
|
|
285
|
+
* @param method Method name to invoke
|
|
286
|
+
* @param params Parameters to pass to the method
|
|
287
|
+
* @returns Promise that resolves with the result
|
|
288
|
+
*/
|
|
289
|
+
this.send = (method, params) => new Promise((resolve, reject) => {
|
|
290
|
+
const request_id = (this.requests.push({ resolve, reject }) - 1).toString();
|
|
291
|
+
if (!this.isAvailable()) {
|
|
292
|
+
this.handleCoreEvent(
|
|
293
|
+
internalResultEvent({
|
|
294
|
+
type: "Error" /* Error */,
|
|
295
|
+
request_id,
|
|
296
|
+
method,
|
|
297
|
+
data: {
|
|
298
|
+
error_message: "Bridge is not available",
|
|
299
|
+
error_type: "BRIDGE_NOT_AVAILABLE" /* BRIDGE_NOT_AVAILABLE */
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
this.sendEvent(
|
|
306
|
+
internalEvent("Request" /* Request */, {
|
|
307
|
+
method,
|
|
308
|
+
params,
|
|
309
|
+
request_id
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
/**
|
|
314
|
+
* Check if a method is supported by the other side
|
|
315
|
+
*/
|
|
316
|
+
this.supports = (method) => this.supportedMethods.includes(method);
|
|
317
|
+
/**
|
|
318
|
+
* Check if the bridge is available (initialized)
|
|
319
|
+
*/
|
|
320
|
+
this.isAvailable = () => this.available;
|
|
321
|
+
this.sendEvent = sendEvent;
|
|
322
|
+
this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// src/BridgeBase.ts
|
|
327
|
+
var BridgeBase = class {
|
|
328
|
+
constructor(bridge) {
|
|
329
|
+
/**
|
|
330
|
+
* Check if a method is supported by the other side
|
|
331
|
+
* @param method Method name to check
|
|
332
|
+
*/
|
|
333
|
+
this.supports = (method) => this.bridge.supports(method);
|
|
334
|
+
/**
|
|
335
|
+
* Check if the bridge is available (initialized)
|
|
336
|
+
*/
|
|
337
|
+
this.isAvailable = () => this.bridge.isAvailable();
|
|
338
|
+
/**
|
|
339
|
+
* Send a request to invoke a method on the other side
|
|
340
|
+
* @param method Method name to invoke
|
|
341
|
+
* @param params Parameters to pass
|
|
342
|
+
* @returns Promise resolving with the result
|
|
343
|
+
*/
|
|
344
|
+
this.send = (method, params = {}) => {
|
|
345
|
+
return this.bridge.send(method, params);
|
|
346
|
+
};
|
|
347
|
+
/**
|
|
348
|
+
* Subscribe to all result events
|
|
349
|
+
* @param listener Callback for result events
|
|
350
|
+
* @returns Subscription index
|
|
351
|
+
*/
|
|
352
|
+
this.subscribe = (listener) => {
|
|
353
|
+
return this.bridge.subscribe(listener);
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* Unsubscribe from result events
|
|
357
|
+
* @param listener The listener to remove
|
|
358
|
+
*/
|
|
359
|
+
this.unsubscribe = (listener) => {
|
|
360
|
+
return this.bridge.unsubscribe(listener);
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* Initialize the bridge with handlers
|
|
364
|
+
* @param handlers Map of method names to handler functions
|
|
365
|
+
* @returns Promise resolving when initialization is complete
|
|
366
|
+
*/
|
|
367
|
+
this.init = (handlers) => this.bridge.init(handlers);
|
|
368
|
+
this.bridge = bridge;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// src/AspectlyBridge.ts
|
|
373
|
+
var AspectlyBridge = class extends BridgeBase {
|
|
374
|
+
constructor(options) {
|
|
375
|
+
const bridge = new BridgeInternal(BridgeCore.sendEvent, options);
|
|
376
|
+
super(bridge);
|
|
377
|
+
/**
|
|
378
|
+
* Cleanup bridge subscriptions
|
|
379
|
+
*/
|
|
380
|
+
this.destroy = () => {
|
|
381
|
+
this.cleanupSubscription();
|
|
382
|
+
};
|
|
383
|
+
this.cleanupSubscription = BridgeCore.subscribe(
|
|
384
|
+
bridge.handleCoreEvent
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// src/browser.ts
|
|
390
|
+
if (typeof window !== "undefined") {
|
|
391
|
+
window.aspectlyBridge = new AspectlyBridge();
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export { AspectlyBridge };
|
|
395
|
+
//# sourceMappingURL=browser.mjs.map
|
|
396
|
+
//# sourceMappingURL=browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/BridgeCore.ts","../src/BridgeInternal.ts","../src/BridgeBase.ts","../src/AspectlyBridge.ts","../src/browser.ts"],"names":[],"mappings":"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","file":"browser.mjs","sourcesContent":["/**\n * Low-level bridge core handling platform-specific message passing\n */\n\nexport type Event = unknown;\n\ninterface BridgeCoreEvent {\n type: string;\n event: Event;\n}\n\ninterface WebViewMessage {\n nativeEvent?: {\n data?: string;\n };\n}\n\nexport type BridgeCoreListener = (event: Event) => void;\n\ndeclare global {\n interface Window {\n ReactNativeWebView?: {\n postMessage: (message: string) => void;\n };\n }\n}\n\n/**\n * BridgeCore handles the low-level platform detection and message serialization.\n * It provides static methods for wrapping events, creating listeners, and sending messages.\n */\nexport class BridgeCore {\n private static BRIDGE_EVENT_TYPE = 'BridgeEvent';\n\n private static isJSONObject = (str: string): boolean => {\n return str.startsWith('{') && str.endsWith('}');\n };\n\n /**\n * Wraps an event in the bridge protocol format\n */\n public static wrapBridgeEvent = (event: Event): string => {\n return JSON.stringify({\n event,\n type: BridgeCore.BRIDGE_EVENT_TYPE,\n });\n };\n\n /**\n * Creates a listener wrapper that parses incoming messages\n */\n static wrapListener =\n (listener: BridgeCoreListener) =>\n (data?: string): void => {\n if (typeof data !== 'string') {\n return;\n }\n if (!data) {\n return;\n }\n let processedData = data;\n // iOS wraps JSON with additional quotes\n if (processedData.startsWith(\"'\") && processedData.endsWith(\"'\")) {\n processedData = processedData.substring(1, processedData.length - 1);\n }\n if (!BridgeCore.isJSONObject(processedData)) {\n return;\n }\n try {\n const eventData: BridgeCoreEvent = JSON.parse(processedData);\n if (!eventData || eventData.type !== BridgeCore.BRIDGE_EVENT_TYPE) {\n return;\n }\n listener(eventData.event);\n } catch {\n // Ignore parse errors\n }\n };\n\n /**\n * Creates a browser-specific message event listener\n */\n static browserListener = (listener: BridgeCoreListener) => {\n const triggerEvent = BridgeCore.wrapListener(listener);\n return (originalEvent: MessageEvent): void => {\n if (!originalEvent?.data) {\n return;\n }\n triggerEvent(originalEvent.data);\n };\n };\n\n /**\n * Creates a React Native WebView message listener\n */\n static webViewListener = (listener: BridgeCoreListener) => {\n const triggerEvent = BridgeCore.wrapListener(listener);\n return (originalEvent: WebViewMessage): void => {\n if (!originalEvent?.nativeEvent?.data) {\n return;\n }\n triggerEvent(originalEvent.nativeEvent.data);\n };\n };\n\n /**\n * Sends an event to the parent context (WebView or iframe parent)\n */\n static sendEvent = (event: Event): void => {\n const bridgeEvent = BridgeCore.wrapBridgeEvent(event);\n if (typeof window === 'undefined') {\n console.warn('Window is undefined');\n return;\n }\n const RNW = window.ReactNativeWebView;\n if (typeof RNW?.postMessage === 'function') {\n RNW.postMessage(`'${bridgeEvent}'`);\n return;\n }\n if (window.parent === window) {\n return;\n }\n window.parent.postMessage(bridgeEvent, '*');\n };\n\n /**\n * Subscribes to window message events\n * @returns Cleanup function to unsubscribe\n */\n static subscribe = (listener: BridgeCoreListener): VoidFunction => {\n const browserListener = BridgeCore.browserListener(listener);\n if (typeof window === 'undefined' || !window.addEventListener) {\n return () => {};\n }\n window.addEventListener('message', browserListener);\n return () => window.removeEventListener('message', browserListener);\n };\n}\n","import type {\n BridgeData,\n BridgeEvent,\n BridgeHandlers,\n BridgeInitEvent,\n BridgeInitResultEvent,\n BridgeListener,\n BridgeOptions,\n BridgeRequestEvent,\n BridgeResultData,\n BridgeResultError,\n BridgeResultEvent,\n} from './types';\nimport {\n BridgeErrorType,\n BridgeEventType,\n BridgeResultType,\n} from './types';\n\n/**\n * Creates a bridge event with the specified type and data\n */\nexport const internalEvent = (\n type: BridgeEventType,\n data: BridgeData\n): BridgeEvent => ({\n type,\n data,\n});\n\n/**\n * Creates a result event\n */\nexport const internalResultEvent = (data: BridgeData): BridgeEvent =>\n internalEvent(BridgeEventType.Result, data);\n\ninterface InternalRequestPromise {\n reject: (error: BridgeResultError) => void;\n resolve: (result: BridgeResultData) => void;\n}\n\ninterface InitPromise {\n reject: () => void;\n resolve: (success: boolean) => void;\n}\n\ntype InternalEventSender = (event: BridgeEvent) => void;\n\nconst DEFAULT_TIMEOUT = 100000;\n\n/**\n * BridgeInternal handles the business logic of the bridge protocol.\n * It manages request/response lifecycle, handler registration, and event routing.\n */\nexport class BridgeInternal {\n private requests: InternalRequestPromise[] = [];\n private handlers: BridgeHandlers = {};\n private available = false;\n private supportedMethods: string[] = [];\n private listeners: BridgeListener[] = [];\n private initPromise?: InitPromise;\n private readonly sendEvent: InternalEventSender;\n private readonly timeout: number;\n\n constructor(sendEvent: InternalEventSender, options?: BridgeOptions) {\n this.sendEvent = sendEvent;\n this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;\n }\n\n /**\n * Subscribe to all result events\n */\n public subscribe = (listener: BridgeListener): number => {\n return this.listeners.push(listener);\n };\n\n /**\n * Unsubscribe from result events\n */\n public unsubscribe = (listener: BridgeListener): void => {\n this.listeners = this.listeners.filter(\n (oldListener) => oldListener !== listener\n );\n };\n\n private checkDiff = (a: string[], b: string[]): boolean => {\n return (\n a.filter((x) => !b.includes(x)).length > 0 ||\n b.filter((x) => !a.includes(x)).length > 0\n );\n };\n\n /**\n * Initialize the bridge with handlers\n * @param handlers Map of method names to handler functions\n * @returns Promise that resolves when the other side acknowledges\n */\n public init = (handlers: BridgeHandlers = {}): Promise<boolean> => {\n const oldMethods = Object.keys(this.handlers);\n const newMethods = Object.keys(handlers);\n this.handlers = handlers;\n if (!this.checkDiff(oldMethods, newMethods)) {\n return Promise.resolve(true);\n }\n return new Promise((resolve, reject) => {\n this.initPromise = { resolve, reject };\n this.sendEvent(\n internalEvent(BridgeEventType.Init, {\n methods: newMethods,\n })\n );\n });\n };\n\n /**\n * Handle incoming bridge events\n */\n public handleCoreEvent = (event: BridgeEvent): void => {\n const { type, data } = event;\n switch (type) {\n case BridgeEventType.Init:\n this.handleInit(data as BridgeInitEvent);\n break;\n case BridgeEventType.InitResult:\n this.handleInitResult(data as BridgeInitResultEvent);\n break;\n case BridgeEventType.Request:\n this.handleRequest(data as BridgeRequestEvent);\n break;\n case BridgeEventType.Result:\n this.handleResult(data as BridgeResultEvent);\n break;\n }\n };\n\n /**\n * Handle incoming requests and execute the appropriate handler\n */\n public handleRequest = (request: BridgeRequestEvent): void => {\n const { method, params, request_id } = request;\n new Promise<BridgeResultData>((resolve, reject) => {\n let timeout = false;\n if (!Object.prototype.hasOwnProperty.call(this.handlers, method)) {\n reject({\n error_type: BridgeErrorType.UNSUPPORTED_METHOD,\n error: new Error(`Handler for «${method}» is not registered`),\n });\n return;\n }\n const timer = setTimeout(() => {\n timeout = true;\n reject({\n error_type: BridgeErrorType.METHOD_EXECUTION_TIMEOUT,\n error: new Error('Execution timeout exceeded'),\n });\n }, this.timeout);\n const handler = this.handlers[method];\n if (!handler) {\n reject({\n error_type: BridgeErrorType.UNSUPPORTED_METHOD,\n error: new Error(`Handler for «${method}» is undefined`),\n });\n return;\n }\n handler(params)\n .then((result) => {\n if (timeout) {\n return;\n }\n clearTimeout(timer);\n resolve(result as BridgeResultData);\n })\n .catch((error: Error) => {\n if (timeout) {\n return;\n }\n clearTimeout(timer);\n reject({\n error_type: BridgeErrorType.REJECTED,\n error: error,\n });\n });\n })\n .then((data: BridgeResultData) => {\n this.sendEvent(\n internalResultEvent({\n type: BridgeResultType.Success,\n data,\n method,\n request_id,\n })\n );\n })\n .catch(\n ({\n error_type,\n error,\n }: {\n error_type: BridgeErrorType;\n error: Error;\n }) => {\n this.sendEvent(\n internalResultEvent({\n type: BridgeResultType.Error,\n request_id,\n method,\n data: {\n error_message: error.message,\n error_type,\n },\n })\n );\n }\n );\n };\n\n private handleResult = (result: BridgeResultEvent): void => {\n this.handleRequestResult(result);\n this.listeners.forEach((listener) => listener(result));\n };\n\n private handleRequestResult = (result: BridgeResultEvent): void => {\n if (!result || !Object.prototype.hasOwnProperty.call(result, 'request_id')) {\n return;\n }\n if (!Object.prototype.hasOwnProperty.call(result, 'type')) {\n console.warn('unknown result', result);\n return;\n }\n const { request_id, data, type } = result;\n const request = this.requests[Number(request_id)];\n if (!request) {\n return;\n }\n if (type === BridgeResultType.Success) {\n request.resolve(data);\n return;\n }\n if (type === BridgeResultType.Error) {\n request.reject(data as BridgeResultError);\n }\n };\n\n private handleInit = (data: BridgeInitEvent): void => {\n this.available = true;\n this.supportedMethods = data.methods;\n this.sendEvent(internalEvent(BridgeEventType.InitResult, true));\n };\n\n private handleInitResult = (success: BridgeInitResultEvent): void => {\n if (success) {\n this.initPromise?.resolve(true);\n } else {\n this.initPromise?.reject();\n }\n };\n\n /**\n * Send a request to the other side\n * @param method Method name to invoke\n * @param params Parameters to pass to the method\n * @returns Promise that resolves with the result\n */\n public send = <TResult = unknown>(\n method: string,\n params: object\n ): Promise<TResult> =>\n new Promise((resolve, reject) => {\n const request_id = (\n this.requests.push({ resolve: resolve as (result: BridgeResultData) => void, reject }) - 1\n ).toString();\n if (!this.isAvailable()) {\n this.handleCoreEvent(\n internalResultEvent({\n type: BridgeResultType.Error,\n request_id,\n method,\n data: {\n error_message: 'Bridge is not available',\n error_type: BridgeErrorType.BRIDGE_NOT_AVAILABLE,\n },\n })\n );\n return;\n }\n this.sendEvent(\n internalEvent(BridgeEventType.Request, {\n method,\n params,\n request_id,\n })\n );\n });\n\n /**\n * Check if a method is supported by the other side\n */\n public supports = (method: string): boolean =>\n this.supportedMethods.includes(method);\n\n /**\n * Check if the bridge is available (initialized)\n */\n public isAvailable = (): boolean => this.available;\n}\n","import type { BridgeHandlers, BridgeListener } from './types';\nimport type { BridgeInternal } from './BridgeInternal';\n\n/**\n * BridgeBase provides the public API for bridge communication.\n * It wraps BridgeInternal and exposes a clean interface for consumers.\n */\nexport class BridgeBase {\n protected bridge: BridgeInternal;\n\n constructor(bridge: BridgeInternal) {\n this.bridge = bridge;\n }\n\n /**\n * Check if a method is supported by the other side\n * @param method Method name to check\n */\n public supports = (method: string): boolean => this.bridge.supports(method);\n\n /**\n * Check if the bridge is available (initialized)\n */\n public isAvailable = (): boolean => this.bridge.isAvailable();\n\n /**\n * Send a request to invoke a method on the other side\n * @param method Method name to invoke\n * @param params Parameters to pass\n * @returns Promise resolving with the result\n */\n public send = <TResult = unknown>(\n method: string,\n params: object = {}\n ): Promise<TResult> => {\n return this.bridge.send<TResult>(method, params);\n };\n\n /**\n * Subscribe to all result events\n * @param listener Callback for result events\n * @returns Subscription index\n */\n public subscribe = (listener: BridgeListener): number => {\n return this.bridge.subscribe(listener);\n };\n\n /**\n * Unsubscribe from result events\n * @param listener The listener to remove\n */\n public unsubscribe = (listener: BridgeListener): void => {\n return this.bridge.unsubscribe(listener);\n };\n\n /**\n * Initialize the bridge with handlers\n * @param handlers Map of method names to handler functions\n * @returns Promise resolving when initialization is complete\n */\n public init = (handlers?: BridgeHandlers): Promise<boolean> =>\n this.bridge.init(handlers);\n}\n","import { BridgeCore } from './BridgeCore';\nimport { BridgeInternal } from './BridgeInternal';\nimport { BridgeBase } from './BridgeBase';\nimport type { BridgeOptions } from './types';\n\n/**\n * AspectlyBridge is the main entry point for bridge communication.\n * Use this class when running inside a WebView or iframe that needs\n * to communicate with its parent container.\n *\n * @example\n * ```typescript\n * // Inside a WebView or iframe\n * const bridge = new AspectlyBridge();\n *\n * // Initialize with handlers\n * await bridge.init({\n * greet: async (params) => {\n * return { message: `Hello, ${params.name}!` };\n * }\n * });\n *\n * // Send messages to parent\n * const result = await bridge.send('someMethod', { data: 'value' });\n * ```\n */\nexport class AspectlyBridge extends BridgeBase {\n private cleanupSubscription: VoidFunction;\n\n constructor(options?: BridgeOptions) {\n const bridge = new BridgeInternal(BridgeCore.sendEvent, options);\n super(bridge);\n this.cleanupSubscription = BridgeCore.subscribe(\n bridge.handleCoreEvent as (event: unknown) => void\n );\n }\n\n /**\n * Cleanup bridge subscriptions\n */\n public destroy = (): void => {\n this.cleanupSubscription();\n };\n}\n","/**\n * Browser entry point for direct script inclusion.\n * Creates a global `aspectlyBridge` instance on the window object.\n *\n * @example\n * ```html\n * <script src=\"https://unpkg.com/@aspectly/core/dist/browser.js\"></script>\n * <script>\n * window.aspectlyBridge.init({\n * greet: async (params) => ({ message: 'Hello!' })\n * });\n * </script>\n * ```\n */\nimport { AspectlyBridge } from './AspectlyBridge';\n\ndeclare global {\n interface Window {\n aspectlyBridge: AspectlyBridge;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.aspectlyBridge = new AspectlyBridge();\n}\n\nexport { AspectlyBridge };\n"]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export { A as AspectlyBridge, B as BridgeBase, c as BridgeData, q as BridgeErrorType, b as BridgeEvent, o as BridgeEventType, d as BridgeHandler, e as BridgeHandlers, m as BridgeInitEvent, n as BridgeInitResultEvent, a as BridgeInternal, f as BridgeListener, g as BridgeOptions, h as BridgeRequestEvent, l as BridgeResultData, j as BridgeResultError, i as BridgeResultEvent, k as BridgeResultSuccess, p as BridgeResultType } from './AspectlyBridge-hGuDjcI6.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Low-level bridge core handling platform-specific message passing
|
|
5
|
+
*/
|
|
6
|
+
type Event = unknown;
|
|
7
|
+
interface WebViewMessage {
|
|
8
|
+
nativeEvent?: {
|
|
9
|
+
data?: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
type BridgeCoreListener = (event: Event) => void;
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
ReactNativeWebView?: {
|
|
16
|
+
postMessage: (message: string) => void;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* BridgeCore handles the low-level platform detection and message serialization.
|
|
22
|
+
* It provides static methods for wrapping events, creating listeners, and sending messages.
|
|
23
|
+
*/
|
|
24
|
+
declare class BridgeCore {
|
|
25
|
+
private static BRIDGE_EVENT_TYPE;
|
|
26
|
+
private static isJSONObject;
|
|
27
|
+
/**
|
|
28
|
+
* Wraps an event in the bridge protocol format
|
|
29
|
+
*/
|
|
30
|
+
static wrapBridgeEvent: (event: Event) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a listener wrapper that parses incoming messages
|
|
33
|
+
*/
|
|
34
|
+
static wrapListener: (listener: BridgeCoreListener) => (data?: string) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a browser-specific message event listener
|
|
37
|
+
*/
|
|
38
|
+
static browserListener: (listener: BridgeCoreListener) => (originalEvent: MessageEvent) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a React Native WebView message listener
|
|
41
|
+
*/
|
|
42
|
+
static webViewListener: (listener: BridgeCoreListener) => (originalEvent: WebViewMessage) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Sends an event to the parent context (WebView or iframe parent)
|
|
45
|
+
*/
|
|
46
|
+
static sendEvent: (event: Event) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Subscribes to window message events
|
|
49
|
+
* @returns Cleanup function to unsubscribe
|
|
50
|
+
*/
|
|
51
|
+
static subscribe: (listener: BridgeCoreListener) => VoidFunction;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { BridgeCore };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export { A as AspectlyBridge, B as BridgeBase, c as BridgeData, q as BridgeErrorType, b as BridgeEvent, o as BridgeEventType, d as BridgeHandler, e as BridgeHandlers, m as BridgeInitEvent, n as BridgeInitResultEvent, a as BridgeInternal, f as BridgeListener, g as BridgeOptions, h as BridgeRequestEvent, l as BridgeResultData, j as BridgeResultError, i as BridgeResultEvent, k as BridgeResultSuccess, p as BridgeResultType } from './AspectlyBridge-hGuDjcI6.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Low-level bridge core handling platform-specific message passing
|
|
5
|
+
*/
|
|
6
|
+
type Event = unknown;
|
|
7
|
+
interface WebViewMessage {
|
|
8
|
+
nativeEvent?: {
|
|
9
|
+
data?: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
type BridgeCoreListener = (event: Event) => void;
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
ReactNativeWebView?: {
|
|
16
|
+
postMessage: (message: string) => void;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* BridgeCore handles the low-level platform detection and message serialization.
|
|
22
|
+
* It provides static methods for wrapping events, creating listeners, and sending messages.
|
|
23
|
+
*/
|
|
24
|
+
declare class BridgeCore {
|
|
25
|
+
private static BRIDGE_EVENT_TYPE;
|
|
26
|
+
private static isJSONObject;
|
|
27
|
+
/**
|
|
28
|
+
* Wraps an event in the bridge protocol format
|
|
29
|
+
*/
|
|
30
|
+
static wrapBridgeEvent: (event: Event) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a listener wrapper that parses incoming messages
|
|
33
|
+
*/
|
|
34
|
+
static wrapListener: (listener: BridgeCoreListener) => (data?: string) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a browser-specific message event listener
|
|
37
|
+
*/
|
|
38
|
+
static browserListener: (listener: BridgeCoreListener) => (originalEvent: MessageEvent) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a React Native WebView message listener
|
|
41
|
+
*/
|
|
42
|
+
static webViewListener: (listener: BridgeCoreListener) => (originalEvent: WebViewMessage) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Sends an event to the parent context (WebView or iframe parent)
|
|
45
|
+
*/
|
|
46
|
+
static sendEvent: (event: Event) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Subscribes to window message events
|
|
49
|
+
* @returns Cleanup function to unsubscribe
|
|
50
|
+
*/
|
|
51
|
+
static subscribe: (listener: BridgeCoreListener) => VoidFunction;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { BridgeCore };
|