signal-bridge 1.0.3 → 1.0.5
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 +249 -0
- package/dist/index.d.mts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.global.js +36 -4
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +39 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# 🚀 Signal Bridge
|
|
2
|
+
|
|
3
|
+
Lightweight communication bridge berbasis `window.postMessage` untuk komunikasi **Host ↔ Iframe (Remote App)** dengan fitur:
|
|
4
|
+
|
|
5
|
+
* 🔐 Optional encryption (AES)
|
|
6
|
+
* 🛡️ Origin validation (security)
|
|
7
|
+
* 🔁 Listener & emitter sederhana
|
|
8
|
+
* ♻️ Singleton instance (init hanya sekali)
|
|
9
|
+
* 🌐 Support UMD (browser global) + npm package
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 📦 Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install signal-bridge
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
atau via CDN (UMD):
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<script src="signal-bridge.umd.js"></script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ⚙️ Konsep Dasar
|
|
28
|
+
|
|
29
|
+
Bridge ini digunakan untuk komunikasi antara:
|
|
30
|
+
|
|
31
|
+
* **Host App** (parent window)
|
|
32
|
+
* **Remote App** (iframe)
|
|
33
|
+
|
|
34
|
+
⚠️ Library ini **hanya berjalan di dalam iframe (remote)**.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🧠 API Overview
|
|
39
|
+
|
|
40
|
+
### 1. Create Bridge (Singleton)
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { createBridge } from "signal-bridge";
|
|
44
|
+
|
|
45
|
+
const bridge = createBridge("my-app-id", {
|
|
46
|
+
allowedHostOrigins: ["https://host.com"],
|
|
47
|
+
cryptoKey: "SECRET_KEY", // optional
|
|
48
|
+
debug: true
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> Hanya akan dibuat **1x (singleton)**. Jika dipanggil ulang, akan reuse instance lama.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### 2. Init Bridge
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
bridge.init();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Mengirim sinyal `"ready"` ke host.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 3. Emit Event ke Host
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
bridge.emit("login", {
|
|
70
|
+
userId: 123,
|
|
71
|
+
token: "abc"
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### 4. Listen Event dari Host
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
bridge.listen((message) => {
|
|
81
|
+
console.log("Received:", message);
|
|
82
|
+
|
|
83
|
+
if (message.type === "logout") {
|
|
84
|
+
// handle logout
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### 5. Akses Global Instance
|
|
92
|
+
|
|
93
|
+
Jika ingin akses dari mana saja:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { signalBridge } from "signal-bridge";
|
|
97
|
+
|
|
98
|
+
signalBridge().emit("ping", {});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
⚠️ Pastikan sudah `createBridge().init()` sebelumnya.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### 6. Reset Bridge
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { resetBridge } from "signal-bridge";
|
|
109
|
+
|
|
110
|
+
resetBridge();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 🔐 Security Features
|
|
116
|
+
|
|
117
|
+
### ✅ Origin Validation
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
allowedHostOrigins: ["https://host.com"]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Hanya origin ini yang bisa kirim message ke iframe.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### ✅ Encryption (Optional)
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
cryptoKey: "SECRET_KEY"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Payload akan otomatis:
|
|
134
|
+
|
|
135
|
+
* Encrypt saat `emit`
|
|
136
|
+
* Decrypt saat `receive`
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 📡 Message Format
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
type BridgeMessage = {
|
|
144
|
+
type: string;
|
|
145
|
+
payload: any;
|
|
146
|
+
txn: string;
|
|
147
|
+
__source: "host" | "remote";
|
|
148
|
+
__origin?: string;
|
|
149
|
+
};
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 🌍 Browser (UMD) Usage
|
|
155
|
+
|
|
156
|
+
```html
|
|
157
|
+
<script>
|
|
158
|
+
const bridge = window.SignalBridge.createBridge("app-id", {
|
|
159
|
+
allowedHostOrigins: ["https://host.com"]
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
bridge.init();
|
|
163
|
+
|
|
164
|
+
bridge.listen((msg) => {
|
|
165
|
+
console.log(msg);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
bridge.emit("hello", { foo: "bar" });
|
|
169
|
+
</script>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 🧪 Example Flow
|
|
175
|
+
|
|
176
|
+
### Remote (Iframe)
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const bridge = createBridge("child-app", {
|
|
180
|
+
allowedHostOrigins: ["https://parent.com"]
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
bridge.init();
|
|
184
|
+
|
|
185
|
+
bridge.listen((msg) => {
|
|
186
|
+
if (msg.type === "user-data") {
|
|
187
|
+
console.log("User:", msg.payload);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
bridge.emit("ready", { status: "ok" });
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## ⚠️ Important Notes
|
|
197
|
+
|
|
198
|
+
* ❗ Harus dijalankan di dalam iframe
|
|
199
|
+
* ❗ `init()` hanya akan trigger sekali (anti duplicate)
|
|
200
|
+
* ❗ Pastikan origin host sesuai (tidak akan menerima jika tidak match)
|
|
201
|
+
* ❗ Encryption hanya aktif jika `cryptoKey` di-set
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 🛠️ Available Exports
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
createBridge
|
|
209
|
+
signalBridge
|
|
210
|
+
resetBridge
|
|
211
|
+
encrypt
|
|
212
|
+
decrypt
|
|
213
|
+
generateKey
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🧩 Internal Behavior
|
|
219
|
+
|
|
220
|
+
* Singleton global instance (`globalBridge`)
|
|
221
|
+
* Anti loop message (`__source` check)
|
|
222
|
+
* Auto ignore invalid message
|
|
223
|
+
* Optional debug logger
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 📄 Source
|
|
228
|
+
|
|
229
|
+
Implementasi utama bisa dilihat di file:
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🧑💻 Author Notes
|
|
236
|
+
|
|
237
|
+
Dirancang untuk kebutuhan komunikasi microfrontend / iframe integration dengan fokus:
|
|
238
|
+
|
|
239
|
+
* Simple API
|
|
240
|
+
* Secure by default
|
|
241
|
+
* Minimal dependency
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 📜 License
|
|
246
|
+
|
|
247
|
+
MIT License © 2026 - EkaHersada
|
|
248
|
+
|
|
249
|
+
---
|
package/dist/index.d.mts
CHANGED
|
@@ -18,11 +18,24 @@ interface BridgeOptions {
|
|
|
18
18
|
debug?: boolean;
|
|
19
19
|
enableNavigationSync?: boolean;
|
|
20
20
|
}
|
|
21
|
-
declare function
|
|
21
|
+
declare function createBridge(appId: string, options: BridgeOptions): {
|
|
22
|
+
init(): void;
|
|
23
|
+
listen(handler: Listener): void;
|
|
24
|
+
emit(type: string, payload: any): void;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
};
|
|
27
|
+
declare function resetBridge(): void;
|
|
28
|
+
declare function signalBridge(): {
|
|
29
|
+
init(): void;
|
|
30
|
+
listen(handler: Listener): void;
|
|
31
|
+
emit(type: string, payload: any): void;
|
|
32
|
+
destroy(): void;
|
|
33
|
+
};
|
|
34
|
+
declare function setupBridge(appId: string, options: BridgeOptions): {
|
|
22
35
|
init(): void;
|
|
23
36
|
listen(handler: Listener): void;
|
|
24
37
|
emit(type: string, payload: any): void;
|
|
25
38
|
destroy(): void;
|
|
26
39
|
};
|
|
27
40
|
|
|
28
|
-
export { base64UrlDecode, base64UrlEncode, decrypt, encrypt, generateKey, signalBridge };
|
|
41
|
+
export { base64UrlDecode, base64UrlEncode, createBridge, decrypt, encrypt, generateKey, resetBridge, setupBridge, signalBridge };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,11 +18,24 @@ interface BridgeOptions {
|
|
|
18
18
|
debug?: boolean;
|
|
19
19
|
enableNavigationSync?: boolean;
|
|
20
20
|
}
|
|
21
|
-
declare function
|
|
21
|
+
declare function createBridge(appId: string, options: BridgeOptions): {
|
|
22
|
+
init(): void;
|
|
23
|
+
listen(handler: Listener): void;
|
|
24
|
+
emit(type: string, payload: any): void;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
};
|
|
27
|
+
declare function resetBridge(): void;
|
|
28
|
+
declare function signalBridge(): {
|
|
29
|
+
init(): void;
|
|
30
|
+
listen(handler: Listener): void;
|
|
31
|
+
emit(type: string, payload: any): void;
|
|
32
|
+
destroy(): void;
|
|
33
|
+
};
|
|
34
|
+
declare function setupBridge(appId: string, options: BridgeOptions): {
|
|
22
35
|
init(): void;
|
|
23
36
|
listen(handler: Listener): void;
|
|
24
37
|
emit(type: string, payload: any): void;
|
|
25
38
|
destroy(): void;
|
|
26
39
|
};
|
|
27
40
|
|
|
28
|
-
export { base64UrlDecode, base64UrlEncode, decrypt, encrypt, generateKey, signalBridge };
|
|
41
|
+
export { base64UrlDecode, base64UrlEncode, createBridge, decrypt, encrypt, generateKey, resetBridge, setupBridge, signalBridge };
|
package/dist/index.global.js
CHANGED
|
@@ -6629,9 +6629,12 @@ var signalBridge = (() => {
|
|
|
6629
6629
|
__export(index_exports, {
|
|
6630
6630
|
base64UrlDecode: () => base64UrlDecode,
|
|
6631
6631
|
base64UrlEncode: () => base64UrlEncode,
|
|
6632
|
+
createBridge: () => createBridge,
|
|
6632
6633
|
decrypt: () => decrypt,
|
|
6633
6634
|
encrypt: () => encrypt,
|
|
6634
6635
|
generateKey: () => generateKey,
|
|
6636
|
+
resetBridge: () => resetBridge,
|
|
6637
|
+
setupBridge: () => setupBridge,
|
|
6635
6638
|
signalBridge: () => signalBridge
|
|
6636
6639
|
});
|
|
6637
6640
|
|
|
@@ -6675,7 +6678,33 @@ var signalBridge = (() => {
|
|
|
6675
6678
|
|
|
6676
6679
|
// src/index.ts
|
|
6677
6680
|
var isInitialized = false;
|
|
6678
|
-
|
|
6681
|
+
var globalConfig = null;
|
|
6682
|
+
var globalBridge = null;
|
|
6683
|
+
function createBridge(appId, options) {
|
|
6684
|
+
if (globalBridge) {
|
|
6685
|
+
if ((globalConfig == null ? void 0 : globalConfig.appId) !== appId || JSON.stringify(globalConfig == null ? void 0 : globalConfig.origins) !== JSON.stringify(options.allowedHostOrigins)) {
|
|
6686
|
+
console.warn("\u26A0\uFE0F Bridge already initialized with different config");
|
|
6687
|
+
}
|
|
6688
|
+
return globalBridge;
|
|
6689
|
+
}
|
|
6690
|
+
globalConfig = {
|
|
6691
|
+
appId,
|
|
6692
|
+
origins: options.allowedHostOrigins
|
|
6693
|
+
};
|
|
6694
|
+
globalBridge = setupBridge(appId, options);
|
|
6695
|
+
return globalBridge;
|
|
6696
|
+
}
|
|
6697
|
+
function resetBridge() {
|
|
6698
|
+
globalBridge == null ? void 0 : globalBridge.destroy();
|
|
6699
|
+
globalBridge = null;
|
|
6700
|
+
}
|
|
6701
|
+
function signalBridge() {
|
|
6702
|
+
if (!globalBridge) {
|
|
6703
|
+
throw new Error("\u274C Bridge belum di-init. Panggil createBridge().init() dulu");
|
|
6704
|
+
}
|
|
6705
|
+
return globalBridge;
|
|
6706
|
+
}
|
|
6707
|
+
function setupBridge(appId, options) {
|
|
6679
6708
|
const { allowedHostOrigins, cryptoKey, debug } = options;
|
|
6680
6709
|
const isRemote = window.parent && window.parent !== window;
|
|
6681
6710
|
if (!isRemote) {
|
|
@@ -6699,14 +6728,14 @@ var signalBridge = (() => {
|
|
|
6699
6728
|
const remoteMessage = {
|
|
6700
6729
|
type: data.type,
|
|
6701
6730
|
payload,
|
|
6702
|
-
txn: data.txn,
|
|
6731
|
+
txn: data.txn || "",
|
|
6703
6732
|
__source: "host",
|
|
6704
6733
|
__origin: origin
|
|
6705
6734
|
};
|
|
6706
6735
|
listeners.forEach((fn) => fn(remoteMessage));
|
|
6707
6736
|
};
|
|
6708
6737
|
window.addEventListener("message", messageHandler);
|
|
6709
|
-
function emitToHost(type, payload) {
|
|
6738
|
+
function emitToHost(type, payload, txn) {
|
|
6710
6739
|
let finalPayload = payload;
|
|
6711
6740
|
if (cryptoKey) {
|
|
6712
6741
|
finalPayload = encrypt(payload, cryptoKey);
|
|
@@ -6715,7 +6744,7 @@ var signalBridge = (() => {
|
|
|
6715
6744
|
app_id: appId,
|
|
6716
6745
|
type,
|
|
6717
6746
|
payload: finalPayload,
|
|
6718
|
-
txn:
|
|
6747
|
+
txn: txn || "",
|
|
6719
6748
|
__origin: window.location.origin,
|
|
6720
6749
|
__source: "remote"
|
|
6721
6750
|
};
|
|
@@ -6752,7 +6781,10 @@ var signalBridge = (() => {
|
|
|
6752
6781
|
}
|
|
6753
6782
|
if (typeof window !== "undefined") {
|
|
6754
6783
|
window.SignalBridge = {
|
|
6784
|
+
createBridge,
|
|
6785
|
+
// 👈 NEW
|
|
6755
6786
|
signalBridge,
|
|
6787
|
+
// 👈 NEW
|
|
6756
6788
|
encrypt,
|
|
6757
6789
|
decrypt,
|
|
6758
6790
|
generateKey
|