@kookapp/web-bridge 0.0.1
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/README.md +144 -0
- package/dist/child/ChildBridge.d.ts +40 -0
- package/dist/child/ChildBridge.d.ts.map +1 -0
- package/dist/child/ChildBridge.js +124 -0
- package/dist/child/index.d.ts +4 -0
- package/dist/child/index.d.ts.map +1 -0
- package/dist/child/index.js +2 -0
- package/dist/child/utils.d.ts +7 -0
- package/dist/child/utils.d.ts.map +1 -0
- package/dist/child/utils.js +22 -0
- package/dist/constants.d.ts +29 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +28 -0
- package/dist/errors/BridgeError.d.ts +21 -0
- package/dist/errors/BridgeError.d.ts.map +1 -0
- package/dist/errors/BridgeError.js +35 -0
- package/dist/errors/errorFactory.d.ts +14 -0
- package/dist/errors/errorFactory.d.ts.map +1 -0
- package/dist/errors/errorFactory.js +13 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/parent/IframeChannel.d.ts +44 -0
- package/dist/parent/IframeChannel.d.ts.map +1 -0
- package/dist/parent/IframeChannel.js +96 -0
- package/dist/parent/ParentBridge.d.ts +41 -0
- package/dist/parent/ParentBridge.d.ts.map +1 -0
- package/dist/parent/ParentBridge.js +101 -0
- package/dist/parent/index.d.ts +6 -0
- package/dist/parent/index.d.ts.map +1 -0
- package/dist/parent/index.js +3 -0
- package/dist/parent/utils.d.ts +6 -0
- package/dist/parent/utils.d.ts.map +1 -0
- package/dist/parent/utils.js +23 -0
- package/dist/shared/EventEmitter.d.ts +13 -0
- package/dist/shared/EventEmitter.d.ts.map +1 -0
- package/dist/shared/EventEmitter.js +47 -0
- package/dist/shared/IdGenerator.d.ts +11 -0
- package/dist/shared/IdGenerator.d.ts.map +1 -0
- package/dist/shared/IdGenerator.js +16 -0
- package/dist/shared/MessageHandler.d.ts +75 -0
- package/dist/shared/MessageHandler.d.ts.map +1 -0
- package/dist/shared/MessageHandler.js +197 -0
- package/dist/shared/OriginValidator.d.ts +14 -0
- package/dist/shared/OriginValidator.d.ts.map +1 -0
- package/dist/shared/OriginValidator.js +53 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# WebBridge
|
|
2
|
+
|
|
3
|
+
A PostMessage-based bridge for iframe communication, providing symmetric callHandler and registerHandler APIs similar to jsbridge but for web environments.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Symmetric API**: Both parent and iframe can call handlers and register responders
|
|
8
|
+
- **PostMessage-based**: Uses native Web APIs for cross-origin communication
|
|
9
|
+
- **Origin Validation**: Strict domain whitelist verification
|
|
10
|
+
- **Type-Safe**: Full TypeScript support with comprehensive type definitions
|
|
11
|
+
- **Promise & Callback**: Supports both async/await and callback patterns
|
|
12
|
+
- **Error Handling**: Comprehensive error codes and timeout management
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @kookapp/web-bridge
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Parent Side (iframe外部)
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { ParentBridge } from '@kookapp/web-bridge'
|
|
26
|
+
|
|
27
|
+
// Initialize the bridge
|
|
28
|
+
const bridge = new ParentBridge({
|
|
29
|
+
allowedOrigins: ['https://iframe.example.com']
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Register a handler that can be called from iframe
|
|
33
|
+
bridge.registerHandler('getUserInfo', (data, callback) => {
|
|
34
|
+
const userInfo = { id: 1, name: 'John' }
|
|
35
|
+
callback(userInfo)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Create a communication channel with an iframe
|
|
39
|
+
const iframeElement = document.getElementById('myIframe') as HTMLIFrameElement
|
|
40
|
+
const channel = bridge.createChannel(iframeElement)
|
|
41
|
+
|
|
42
|
+
// Call a handler inside iframe
|
|
43
|
+
channel.callHandler('getIframeData', { type: 'user' })
|
|
44
|
+
.then(result => console.log('Result:', result))
|
|
45
|
+
.catch(error => console.error('Error:', error))
|
|
46
|
+
|
|
47
|
+
// Clean up
|
|
48
|
+
// bridge.destroy()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Child Side (iframe内部)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { ChildBridge } from '@kookapp/web-bridge'
|
|
55
|
+
|
|
56
|
+
// Initialize the bridge
|
|
57
|
+
const bridge = new ChildBridge({
|
|
58
|
+
allowedOrigins: ['https://parent.example.com']
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Register a handler that can be called from parent
|
|
62
|
+
bridge.registerHandler('getIframeData', (data, callback) => {
|
|
63
|
+
const response = { data: 'from iframe', type: data.type }
|
|
64
|
+
callback(response)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Call a handler on parent
|
|
68
|
+
bridge.callHandler('getUserInfo', {})
|
|
69
|
+
.then(userInfo => console.log('User:', userInfo))
|
|
70
|
+
.catch(error => console.error('Error:', error))
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API Reference
|
|
74
|
+
|
|
75
|
+
### ParentBridge
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
class ParentBridge {
|
|
79
|
+
constructor(config: BridgeConfig)
|
|
80
|
+
registerHandler(handlerName: string, handler: Handler): void
|
|
81
|
+
createChannel(iframe: HTMLIFrameElement, options?: { origin: string }): IframeChannel
|
|
82
|
+
unregisterHandler(handlerName: string): void
|
|
83
|
+
destroy(): void
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### IframeChannel
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
interface IframeChannel {
|
|
91
|
+
callHandler(handlerName: string, data?: any, callback?: (result: any) => void): Promise<any>
|
|
92
|
+
getIframe(): HTMLIFrameElement
|
|
93
|
+
isConnected(): boolean
|
|
94
|
+
destroy(): void
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### ChildBridge
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
class ChildBridge {
|
|
102
|
+
constructor(config: BridgeConfig)
|
|
103
|
+
callHandler(handlerName: string, data?: any, callback?: (result: any) => void): Promise<any>
|
|
104
|
+
registerHandler(handlerName: string, handler: Handler): void
|
|
105
|
+
unregisterHandler(handlerName: string): void
|
|
106
|
+
destroy(): void
|
|
107
|
+
isConnected(): boolean
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### BridgeConfig
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
interface BridgeConfig {
|
|
115
|
+
allowedOrigins: string[] // Domain whitelist (supports exact match, regex, and wildcard)
|
|
116
|
+
timeout?: number // Message timeout in ms (default: 5000)
|
|
117
|
+
debug?: boolean // Enable debug logging
|
|
118
|
+
maxRetries?: number // Maximum retry attempts (default: 0)
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Error Handling
|
|
123
|
+
|
|
124
|
+
The bridge throws `BridgeError` with specific error codes:
|
|
125
|
+
|
|
126
|
+
- `HANDLER_NOT_FOUND`: Handler not found on the other side
|
|
127
|
+
- `ORIGIN_NOT_ALLOWED`: Message origin not in whitelist
|
|
128
|
+
- `TIMEOUT`: Request exceeded timeout
|
|
129
|
+
- `INVALID_MESSAGE`: Malformed message received
|
|
130
|
+
- `CONNECTION_LOST`: Connection to other side lost
|
|
131
|
+
|
|
132
|
+
## Security
|
|
133
|
+
|
|
134
|
+
### Origin Validation
|
|
135
|
+
|
|
136
|
+
- Exact match: `'https://example.com'`
|
|
137
|
+
- Regex pattern: `'^https://.*\\.example\\.com$'`
|
|
138
|
+
- Wildcard (dev only): `'*'`
|
|
139
|
+
|
|
140
|
+
Origins are validated for both incoming and outgoing messages.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChildBridge for communication from inside an iframe
|
|
3
|
+
*/
|
|
4
|
+
import { ChildBridgeConfig, BridgeMessage } from '@/types';
|
|
5
|
+
import { MessageHandler } from '@/shared/MessageHandler';
|
|
6
|
+
export declare class ChildBridge extends MessageHandler {
|
|
7
|
+
private parentWindow;
|
|
8
|
+
private parentOrigin;
|
|
9
|
+
private connected;
|
|
10
|
+
constructor(config: ChildBridgeConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Get parent origin
|
|
13
|
+
*/
|
|
14
|
+
private getParentOrigin;
|
|
15
|
+
/**
|
|
16
|
+
* Notify parent that child is ready
|
|
17
|
+
*/
|
|
18
|
+
private notifyReady;
|
|
19
|
+
/**
|
|
20
|
+
* Call a handler on parent
|
|
21
|
+
*/
|
|
22
|
+
callHandler(handlerName: string, data?: any, callback?: (result: any) => void): Promise<any>;
|
|
23
|
+
/**
|
|
24
|
+
* Send message to parent
|
|
25
|
+
*/
|
|
26
|
+
protected sendMessage(targetOrigin: string, message: BridgeMessage): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get target origin
|
|
29
|
+
*/
|
|
30
|
+
protected getTargetOrigin(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Check if connected to parent
|
|
33
|
+
*/
|
|
34
|
+
isConnected(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Destroy the bridge
|
|
37
|
+
*/
|
|
38
|
+
destroy(): void;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=ChildBridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChildBridge.d.ts","sourceRoot":"","sources":["../../src/child/ChildBridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAGxD,qBAAa,WAAY,SAAQ,cAAc;IAC7C,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAiB;gBAEtB,MAAM,EAAE,iBAAiB;IA+BrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAyBvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,GAAG,EACV,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAC/B,OAAO,CAAC,GAAG,CAAC;IAUf;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAezE;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;IAInC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,OAAO,IAAI,IAAI;CAQhB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChildBridge for communication from inside an iframe
|
|
3
|
+
*/
|
|
4
|
+
import { MessageHandler } from '@/shared/MessageHandler';
|
|
5
|
+
import { DEFAULT_TIMEOUT } from '@/constants';
|
|
6
|
+
export class ChildBridge extends MessageHandler {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
const timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
9
|
+
super(config.allowedOrigins, timeout, config.debug);
|
|
10
|
+
this.connected = false;
|
|
11
|
+
// Get parent window and origin
|
|
12
|
+
this.parentWindow = window.parent;
|
|
13
|
+
this.parentOrigin = this.getParentOrigin(config.allowedOrigins);
|
|
14
|
+
// Setup message listener
|
|
15
|
+
this.setupMessageListener((event) => {
|
|
16
|
+
// Only accept messages from parent
|
|
17
|
+
if (event.source === this.parentWindow) {
|
|
18
|
+
this.handleMessage(event.data, event.origin);
|
|
19
|
+
if (!this.connected) {
|
|
20
|
+
this.connected = true;
|
|
21
|
+
this.eventEmitter.emit('ready');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
// Notify parent that we're ready
|
|
26
|
+
this.notifyReady();
|
|
27
|
+
if (this.debug) {
|
|
28
|
+
console.log('[WebBridge] ChildBridge initialized', {
|
|
29
|
+
parentOrigin: this.parentOrigin,
|
|
30
|
+
allowedOrigins: config.allowedOrigins
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get parent origin
|
|
36
|
+
*/
|
|
37
|
+
getParentOrigin(allowedOrigins) {
|
|
38
|
+
// If wildcard is allowed, use it
|
|
39
|
+
if (allowedOrigins.includes('*')) {
|
|
40
|
+
return '*';
|
|
41
|
+
}
|
|
42
|
+
// Try to get document.referrer as parent origin
|
|
43
|
+
if (document.referrer) {
|
|
44
|
+
try {
|
|
45
|
+
return new URL(document.referrer).origin;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// If referrer is not a valid URL, fall back to *
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Fall back to the first allowed origin if it's specific
|
|
52
|
+
const specificOrigins = allowedOrigins.filter(o => o !== '*');
|
|
53
|
+
if (specificOrigins.length > 0) {
|
|
54
|
+
return specificOrigins[0];
|
|
55
|
+
}
|
|
56
|
+
// Last resort: use wildcard
|
|
57
|
+
return '*';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Notify parent that child is ready
|
|
61
|
+
*/
|
|
62
|
+
notifyReady() {
|
|
63
|
+
try {
|
|
64
|
+
this.parentWindow.postMessage({
|
|
65
|
+
type: 'ready',
|
|
66
|
+
_version: '1.0.0'
|
|
67
|
+
}, this.parentOrigin);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (this.debug) {
|
|
71
|
+
console.warn('[WebBridge] Failed to notify parent:', error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Call a handler on parent
|
|
77
|
+
*/
|
|
78
|
+
async callHandler(handlerName, data, callback) {
|
|
79
|
+
const promise = this.callHandlerWithTimeout(this.parentOrigin, handlerName, data);
|
|
80
|
+
if (callback) {
|
|
81
|
+
promise.then(callback).catch(error => console.error(error));
|
|
82
|
+
}
|
|
83
|
+
return promise;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Send message to parent
|
|
87
|
+
*/
|
|
88
|
+
sendMessage(targetOrigin, message) {
|
|
89
|
+
try {
|
|
90
|
+
message._version = '1.0.0';
|
|
91
|
+
this.parentWindow.postMessage(message, targetOrigin);
|
|
92
|
+
if (this.debug) {
|
|
93
|
+
console.log('[WebBridge] Sent message to parent:', message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (this.debug) {
|
|
98
|
+
console.error('[WebBridge] Failed to send message to parent:', error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get target origin
|
|
104
|
+
*/
|
|
105
|
+
getTargetOrigin() {
|
|
106
|
+
return this.parentOrigin;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if connected to parent
|
|
110
|
+
*/
|
|
111
|
+
isConnected() {
|
|
112
|
+
return this.connected;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Destroy the bridge
|
|
116
|
+
*/
|
|
117
|
+
destroy() {
|
|
118
|
+
this.connected = false;
|
|
119
|
+
super.destroy();
|
|
120
|
+
if (this.debug) {
|
|
121
|
+
console.log('[WebBridge] ChildBridge destroyed');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/child/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAChD,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/child/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,UAAU,IAAI,OAAO,CAMpC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAMrC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for child bridge
|
|
3
|
+
*/
|
|
4
|
+
export function isInIframe() {
|
|
5
|
+
try {
|
|
6
|
+
return window.self !== window.top;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function getParentWindow() {
|
|
13
|
+
return window.parent;
|
|
14
|
+
}
|
|
15
|
+
export function getTopWindow() {
|
|
16
|
+
try {
|
|
17
|
+
return window.top || window;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return window;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for WebBridge
|
|
3
|
+
*/
|
|
4
|
+
export declare const BRIDGE_VERSION = "1.0.0";
|
|
5
|
+
export declare const DEFAULT_TIMEOUT = 5000;
|
|
6
|
+
export declare const DEFAULT_MAX_RETRIES = 0;
|
|
7
|
+
export declare const MESSAGE_TYPE: {
|
|
8
|
+
CALL: "call";
|
|
9
|
+
RESPONSE: "response";
|
|
10
|
+
REGISTER: "register";
|
|
11
|
+
READY: "ready";
|
|
12
|
+
};
|
|
13
|
+
export declare const ERROR_CODE: {
|
|
14
|
+
readonly HANDLER_NOT_FOUND: "HANDLER_NOT_FOUND";
|
|
15
|
+
readonly ORIGIN_NOT_ALLOWED: "ORIGIN_NOT_ALLOWED";
|
|
16
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
17
|
+
readonly INVALID_MESSAGE: "INVALID_MESSAGE";
|
|
18
|
+
readonly CONNECTION_LOST: "CONNECTION_LOST";
|
|
19
|
+
readonly INVALID_CONFIG: "INVALID_CONFIG";
|
|
20
|
+
};
|
|
21
|
+
export declare const ERROR_MESSAGE: {
|
|
22
|
+
readonly HANDLER_NOT_FOUND: "Handler not found";
|
|
23
|
+
readonly ORIGIN_NOT_ALLOWED: "Origin not allowed";
|
|
24
|
+
readonly TIMEOUT: "Request timeout";
|
|
25
|
+
readonly INVALID_MESSAGE: "Invalid message format";
|
|
26
|
+
readonly CONNECTION_LOST: "Connection lost";
|
|
27
|
+
readonly INVALID_CONFIG: "Invalid configuration";
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,cAAc,UAAU,CAAA;AAErC,eAAO,MAAM,eAAe,OAAO,CAAA;AAEnC,eAAO,MAAM,mBAAmB,IAAI,CAAA;AAEpC,eAAO,MAAM,YAAY;;;;;CAKxB,CAAA;AAED,eAAO,MAAM,UAAU;;;;;;;CAOb,CAAA;AAEV,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for WebBridge
|
|
3
|
+
*/
|
|
4
|
+
export const BRIDGE_VERSION = '1.0.0';
|
|
5
|
+
export const DEFAULT_TIMEOUT = 5000; // 5 seconds
|
|
6
|
+
export const DEFAULT_MAX_RETRIES = 0;
|
|
7
|
+
export const MESSAGE_TYPE = {
|
|
8
|
+
CALL: 'call',
|
|
9
|
+
RESPONSE: 'response',
|
|
10
|
+
REGISTER: 'register',
|
|
11
|
+
READY: 'ready'
|
|
12
|
+
};
|
|
13
|
+
export const ERROR_CODE = {
|
|
14
|
+
HANDLER_NOT_FOUND: 'HANDLER_NOT_FOUND',
|
|
15
|
+
ORIGIN_NOT_ALLOWED: 'ORIGIN_NOT_ALLOWED',
|
|
16
|
+
TIMEOUT: 'TIMEOUT',
|
|
17
|
+
INVALID_MESSAGE: 'INVALID_MESSAGE',
|
|
18
|
+
CONNECTION_LOST: 'CONNECTION_LOST',
|
|
19
|
+
INVALID_CONFIG: 'INVALID_CONFIG'
|
|
20
|
+
};
|
|
21
|
+
export const ERROR_MESSAGE = {
|
|
22
|
+
[ERROR_CODE.HANDLER_NOT_FOUND]: 'Handler not found',
|
|
23
|
+
[ERROR_CODE.ORIGIN_NOT_ALLOWED]: 'Origin not allowed',
|
|
24
|
+
[ERROR_CODE.TIMEOUT]: 'Request timeout',
|
|
25
|
+
[ERROR_CODE.INVALID_MESSAGE]: 'Invalid message format',
|
|
26
|
+
[ERROR_CODE.CONNECTION_LOST]: 'Connection lost',
|
|
27
|
+
[ERROR_CODE.INVALID_CONFIG]: 'Invalid configuration'
|
|
28
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for WebBridge
|
|
3
|
+
*/
|
|
4
|
+
import { ERROR_CODE } from '@/constants';
|
|
5
|
+
export type BridgeErrorCode = keyof typeof ERROR_CODE;
|
|
6
|
+
export declare class BridgeError extends Error {
|
|
7
|
+
code: BridgeErrorCode;
|
|
8
|
+
originalError?: Error;
|
|
9
|
+
constructor(code: BridgeErrorCode, message?: string, originalError?: Error);
|
|
10
|
+
static create(code: BridgeErrorCode, message?: string, originalError?: Error): BridgeError;
|
|
11
|
+
static isHandlerNotFound(error: any): boolean;
|
|
12
|
+
static isOriginNotAllowed(error: any): boolean;
|
|
13
|
+
static isTimeout(error: any): boolean;
|
|
14
|
+
toJSON(): {
|
|
15
|
+
name: string;
|
|
16
|
+
code: "HANDLER_NOT_FOUND" | "ORIGIN_NOT_ALLOWED" | "TIMEOUT" | "INVALID_MESSAGE" | "CONNECTION_LOST" | "INVALID_CONFIG";
|
|
17
|
+
message: string;
|
|
18
|
+
originalError: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=BridgeError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BridgeError.d.ts","sourceRoot":"","sources":["../../src/errors/BridgeError.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAiB,MAAM,aAAa,CAAA;AAEvD,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,UAAU,CAAA;AAErD,qBAAa,WAAY,SAAQ,KAAK;IACpC,IAAI,EAAE,eAAe,CAAA;IACrB,aAAa,CAAC,EAAE,KAAK,CAAA;gBAET,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,KAAK;IAW1E,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,KAAK,GAAG,WAAW;IAI1F,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;IAI7C,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;IAI9C,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;IAIrC,MAAM;;;;;;CAQP"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for WebBridge
|
|
3
|
+
*/
|
|
4
|
+
import { ERROR_MESSAGE } from '@/constants';
|
|
5
|
+
export class BridgeError extends Error {
|
|
6
|
+
constructor(code, message, originalError) {
|
|
7
|
+
const errorMessage = message || ERROR_MESSAGE[code] || 'Unknown error';
|
|
8
|
+
super(errorMessage);
|
|
9
|
+
this.name = 'BridgeError';
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.originalError = originalError;
|
|
12
|
+
// Maintain proper prototype chain for instanceof checks
|
|
13
|
+
Object.setPrototypeOf(this, BridgeError.prototype);
|
|
14
|
+
}
|
|
15
|
+
static create(code, message, originalError) {
|
|
16
|
+
return new BridgeError(code, message, originalError);
|
|
17
|
+
}
|
|
18
|
+
static isHandlerNotFound(error) {
|
|
19
|
+
return error instanceof BridgeError && error.code === 'HANDLER_NOT_FOUND';
|
|
20
|
+
}
|
|
21
|
+
static isOriginNotAllowed(error) {
|
|
22
|
+
return error instanceof BridgeError && error.code === 'ORIGIN_NOT_ALLOWED';
|
|
23
|
+
}
|
|
24
|
+
static isTimeout(error) {
|
|
25
|
+
return error instanceof BridgeError && error.code === 'TIMEOUT';
|
|
26
|
+
}
|
|
27
|
+
toJSON() {
|
|
28
|
+
return {
|
|
29
|
+
name: this.name,
|
|
30
|
+
code: this.code,
|
|
31
|
+
message: this.message,
|
|
32
|
+
originalError: this.originalError?.message
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error factory functions
|
|
3
|
+
*/
|
|
4
|
+
import { BridgeError, BridgeErrorCode } from '@/errors/BridgeError';
|
|
5
|
+
export declare const errorFactory: {
|
|
6
|
+
handlerNotFound: (handlerName: string) => BridgeError;
|
|
7
|
+
originNotAllowed: (origin: string) => BridgeError;
|
|
8
|
+
timeout: (timeout: number) => BridgeError;
|
|
9
|
+
invalidMessage: (message: string) => BridgeError;
|
|
10
|
+
connectionLost: () => BridgeError;
|
|
11
|
+
invalidConfig: (message: string) => BridgeError;
|
|
12
|
+
wrap: (code: BridgeErrorCode, originalError: Error, message?: string) => BridgeError;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=errorFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorFactory.d.ts","sourceRoot":"","sources":["../../src/errors/errorFactory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEnE,eAAO,MAAM,YAAY;mCACQ,MAAM;+BAGV,MAAM;uBAGd,MAAM;8BAGC,MAAM;;6BAMP,MAAM;iBAGlB,eAAe,iBAAiB,KAAK,YAAY,MAAM;CAErE,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error factory functions
|
|
3
|
+
*/
|
|
4
|
+
import { BridgeError } from '@/errors/BridgeError';
|
|
5
|
+
export const errorFactory = {
|
|
6
|
+
handlerNotFound: (handlerName) => BridgeError.create('HANDLER_NOT_FOUND', `Handler "${handlerName}" not found`),
|
|
7
|
+
originNotAllowed: (origin) => BridgeError.create('ORIGIN_NOT_ALLOWED', `Origin "${origin}" not allowed`),
|
|
8
|
+
timeout: (timeout) => BridgeError.create('TIMEOUT', `Request timeout after ${timeout}ms`),
|
|
9
|
+
invalidMessage: (message) => BridgeError.create('INVALID_MESSAGE', `Invalid message: ${message}`),
|
|
10
|
+
connectionLost: () => BridgeError.create('CONNECTION_LOST', 'Connection to the other side was lost'),
|
|
11
|
+
invalidConfig: (message) => BridgeError.create('INVALID_CONFIG', `Invalid configuration: ${message}`),
|
|
12
|
+
wrap: (code, originalError, message) => BridgeError.create(code, message || originalError.message, originalError)
|
|
13
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for WebBridge
|
|
3
|
+
*/
|
|
4
|
+
export { ParentBridge } from '@/parent/index';
|
|
5
|
+
export type { ParentBridgeConfig, IframeChannelInterface } from '@/parent/index';
|
|
6
|
+
export { IframeChannel } from '@/parent/IframeChannel';
|
|
7
|
+
export { ChildBridge } from '@/child/index';
|
|
8
|
+
export type { ChildBridgeConfig } from '@/child/index';
|
|
9
|
+
export type { BridgeConfig, BridgeMessage, Handler, HandlerRegistry, MessageType } from '@/types';
|
|
10
|
+
export { BridgeError } from '@/errors/BridgeError';
|
|
11
|
+
export type { BridgeErrorCode } from '@/errors/BridgeError';
|
|
12
|
+
export { errorFactory } from '@/errors/errorFactory';
|
|
13
|
+
export { BRIDGE_VERSION, DEFAULT_TIMEOUT, ERROR_CODE, MESSAGE_TYPE } from '@/constants';
|
|
14
|
+
export { EventEmitter } from '@/shared/EventEmitter';
|
|
15
|
+
export { OriginValidator } from '@/shared/OriginValidator';
|
|
16
|
+
export { IdGenerator } from '@/shared/IdGenerator';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAGtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAGtD,YAAY,EACV,YAAY,EACZ,aAAa,EACb,OAAO,EACP,eAAe,EACf,WAAW,EACZ,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAGpD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGvF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for WebBridge
|
|
3
|
+
*/
|
|
4
|
+
// Export parent bridge
|
|
5
|
+
export { ParentBridge } from '@/parent/index';
|
|
6
|
+
export { IframeChannel } from '@/parent/IframeChannel';
|
|
7
|
+
// Export child bridge
|
|
8
|
+
export { ChildBridge } from '@/child/index';
|
|
9
|
+
// Export error handling
|
|
10
|
+
export { BridgeError } from '@/errors/BridgeError';
|
|
11
|
+
export { errorFactory } from '@/errors/errorFactory';
|
|
12
|
+
// Export constants
|
|
13
|
+
export { BRIDGE_VERSION, DEFAULT_TIMEOUT, ERROR_CODE, MESSAGE_TYPE } from '@/constants';
|
|
14
|
+
// Export utilities
|
|
15
|
+
export { EventEmitter } from '@/shared/EventEmitter';
|
|
16
|
+
export { OriginValidator } from '@/shared/OriginValidator';
|
|
17
|
+
export { IdGenerator } from '@/shared/IdGenerator';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IframeChannel for managing communication with a specific iframe
|
|
3
|
+
*/
|
|
4
|
+
import { BridgeMessage, IframeChannelInterface } from '@/types';
|
|
5
|
+
import { MessageHandler } from '@/shared/MessageHandler';
|
|
6
|
+
export declare class IframeChannel extends MessageHandler implements IframeChannelInterface {
|
|
7
|
+
private iframe;
|
|
8
|
+
private iframeOrigin;
|
|
9
|
+
private connected;
|
|
10
|
+
constructor(iframe: HTMLIFrameElement, allowedOrigins: string[], timeout?: number, debug?: boolean);
|
|
11
|
+
/**
|
|
12
|
+
* Extract origin from URL
|
|
13
|
+
*/
|
|
14
|
+
private extractOrigin;
|
|
15
|
+
/**
|
|
16
|
+
* Call a handler in the iframe
|
|
17
|
+
*/
|
|
18
|
+
callHandler(handlerName: string, data?: any, callback?: (result: any) => void): Promise<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Send message to iframe
|
|
21
|
+
*/
|
|
22
|
+
protected sendMessage(targetOrigin: string, message: BridgeMessage): void;
|
|
23
|
+
/**
|
|
24
|
+
* Get target origin (for this channel, it's the iframe origin)
|
|
25
|
+
*/
|
|
26
|
+
protected getTargetOrigin(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Get the iframe element
|
|
29
|
+
*/
|
|
30
|
+
getIframe(): HTMLIFrameElement;
|
|
31
|
+
/**
|
|
32
|
+
* Check if connected
|
|
33
|
+
*/
|
|
34
|
+
isConnected(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Set connected status
|
|
37
|
+
*/
|
|
38
|
+
setConnected(connected: boolean): void;
|
|
39
|
+
/**
|
|
40
|
+
* Destroy the channel
|
|
41
|
+
*/
|
|
42
|
+
destroy(): void;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=IframeChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IframeChannel.d.ts","sourceRoot":"","sources":["../../src/parent/IframeChannel.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD,qBAAa,aAAc,SAAQ,cAAe,YAAW,sBAAsB;IACjF,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAiB;gBAGhC,MAAM,EAAE,iBAAiB,EACzB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,GAAE,MAAa,EACtB,KAAK,GAAE,OAAe;IAmBxB;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,GAAG,EACV,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAC/B,OAAO,CAAC,GAAG,CAAC;IAcf;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAkBzE;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;IAInC;;OAEG;IACH,SAAS,IAAI,iBAAiB;IAI9B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAItC;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB"}
|