@webview-bridge/web 1.1.2 → 1.3.0-nightly.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/dist/commonjs/index.cjs +155 -35
- package/dist/module/index.mjs +154 -35
- package/dist/typescript/packages/web/src/emitter.d.ts +1 -0
- package/dist/typescript/packages/web/src/index.d.ts +2 -0
- package/dist/typescript/packages/web/src/linkBridge.d.ts +9 -0
- package/dist/typescript/packages/web/src/linkBridgeStore.d.ts +6 -0
- package/dist/typescript/packages/web/src/linkNativeMethod.d.ts +7 -7
- package/dist/typescript/packages/web/src/registerWebMethod.d.ts +2 -2
- package/dist/typescript/packages/web/src/types/index.d.ts +4 -3
- package/dist/typescript/shared/util/src/createEvents.d.ts +1 -1
- package/dist/typescript/shared/util/src/equals.d.ts +1 -0
- package/dist/typescript/shared/util/src/index.d.ts +2 -0
- package/dist/typescript/shared/util/src/removeUndefinedKeys.d.ts +1 -0
- package/dist/typescript/shared/util/src/types.d.ts +23 -0
- package/package.json +2 -2
package/dist/commonjs/index.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
MethodNotFoundError: () => MethodNotFoundError,
|
|
24
24
|
NativeMethodError: () => NativeMethodError,
|
|
25
|
+
linkBridge: () => linkBridge,
|
|
25
26
|
linkNativeMethod: () => linkNativeMethod,
|
|
26
27
|
registerWebMethod: () => registerWebMethod
|
|
27
28
|
});
|
|
@@ -57,10 +58,10 @@ var createEvents = () => ({
|
|
|
57
58
|
};
|
|
58
59
|
}
|
|
59
60
|
});
|
|
60
|
-
var createResolver = (emitter2,
|
|
61
|
+
var createResolver = (emitter2, methodName, eventId, evaluate, failHandler = false) => {
|
|
61
62
|
return new Promise((resolve, reject) => {
|
|
62
63
|
const unbind = emitter2.on(
|
|
63
|
-
`${
|
|
64
|
+
`${methodName}-${eventId}`,
|
|
64
65
|
(data, throwOccurred) => {
|
|
65
66
|
unbind();
|
|
66
67
|
if (throwOccurred) {
|
|
@@ -89,6 +90,63 @@ var createRandomId = (size = ID_LENGTH) => {
|
|
|
89
90
|
return randomValues.join("");
|
|
90
91
|
};
|
|
91
92
|
|
|
93
|
+
// ../../shared/util/src/equals.ts
|
|
94
|
+
var equals = (a, b) => {
|
|
95
|
+
if (a === b) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
99
|
+
const arrA = Array.isArray(a);
|
|
100
|
+
const arrB = Array.isArray(b);
|
|
101
|
+
let i;
|
|
102
|
+
let length;
|
|
103
|
+
let key;
|
|
104
|
+
if (arrA && arrB) {
|
|
105
|
+
length = a.length;
|
|
106
|
+
if (length !== b.length) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
for (i = length; i-- !== 0; ) {
|
|
110
|
+
if (!equals(a[i], b[i])) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
if (arrA !== arrB) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const keys = Object.keys(a);
|
|
120
|
+
length = keys.length;
|
|
121
|
+
if (length !== Object.keys(b).length) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
for (i = length; i-- !== 0; ) {
|
|
125
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (i = length; i-- !== 0; ) {
|
|
130
|
+
key = keys[i];
|
|
131
|
+
if (!equals(a[key], b[key])) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
return a !== a && b !== b;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// ../../shared/util/src/removeUndefinedKeys.tsx
|
|
141
|
+
var removeUndefinedKeys = (obj) => {
|
|
142
|
+
Object.keys(obj).forEach((key) => {
|
|
143
|
+
if (obj[key] === void 0) {
|
|
144
|
+
delete obj[key];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
return obj;
|
|
148
|
+
};
|
|
149
|
+
|
|
92
150
|
// ../../shared/util/src/timeout.ts
|
|
93
151
|
var timeout = (ms, throwOnError = true) => {
|
|
94
152
|
return new Promise((resolve, reject) => {
|
|
@@ -102,40 +160,89 @@ var timeout = (ms, throwOnError = true) => {
|
|
|
102
160
|
});
|
|
103
161
|
};
|
|
104
162
|
|
|
105
|
-
// src/
|
|
163
|
+
// src/emitter.ts
|
|
106
164
|
var emitter = createEvents();
|
|
107
|
-
|
|
165
|
+
|
|
166
|
+
// src/linkBridgeStore.ts
|
|
167
|
+
var linkBridgeStore = (initialState = {}) => {
|
|
168
|
+
if (!window.ReactNativeWebView) {
|
|
169
|
+
console.warn("[WebViewBridge] Not in a WebView environment");
|
|
170
|
+
}
|
|
171
|
+
if (!window.nativeEmitter) {
|
|
172
|
+
window.nativeEmitter = emitter;
|
|
173
|
+
}
|
|
174
|
+
const getState = () => state;
|
|
175
|
+
const setState = (newState) => {
|
|
176
|
+
const _newState = {
|
|
177
|
+
...state,
|
|
178
|
+
...removeUndefinedKeys(newState)
|
|
179
|
+
};
|
|
180
|
+
if (equals(state, _newState)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const prevState = state;
|
|
184
|
+
state = _newState;
|
|
185
|
+
emitChange(state, prevState);
|
|
186
|
+
};
|
|
187
|
+
emitter.on("bridgeStateChange", (data) => {
|
|
188
|
+
setState(data);
|
|
189
|
+
});
|
|
190
|
+
window.ReactNativeWebView?.postMessage(
|
|
191
|
+
JSON.stringify({
|
|
192
|
+
type: "getBridgeState"
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
let state = { ...initialState, ...window.__bridgeInitialState__ };
|
|
196
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
197
|
+
const emitChange = (newState, prevState) => {
|
|
198
|
+
for (const listener of listeners) {
|
|
199
|
+
listener(newState, prevState);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const subscribe = (listener) => {
|
|
203
|
+
listeners.add(listener);
|
|
204
|
+
return () => listeners.delete(listener);
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
getState,
|
|
208
|
+
subscribe
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// src/linkBridge.ts
|
|
213
|
+
var createNativeMethod = (methodName, timeoutMs, throwOnError) => (...args) => {
|
|
108
214
|
const eventId = createRandomId();
|
|
109
215
|
return Promise.race([
|
|
110
216
|
createResolver(
|
|
111
217
|
emitter,
|
|
112
|
-
|
|
218
|
+
methodName,
|
|
113
219
|
eventId,
|
|
114
220
|
() => {
|
|
115
221
|
window.ReactNativeWebView?.postMessage(
|
|
116
222
|
JSON.stringify({
|
|
117
223
|
type: "bridge",
|
|
118
224
|
body: {
|
|
119
|
-
method,
|
|
225
|
+
method: methodName,
|
|
120
226
|
eventId,
|
|
121
227
|
args
|
|
122
228
|
}
|
|
123
229
|
})
|
|
124
230
|
);
|
|
125
231
|
},
|
|
126
|
-
throwOnError && new NativeMethodError(
|
|
232
|
+
throwOnError && new NativeMethodError(methodName)
|
|
127
233
|
),
|
|
128
234
|
timeout(timeoutMs, throwOnError)
|
|
129
235
|
]);
|
|
130
236
|
};
|
|
131
|
-
var
|
|
237
|
+
var linkBridge = (options = {
|
|
132
238
|
timeout: 2e3,
|
|
133
239
|
throwOnError: false
|
|
134
240
|
}) => {
|
|
135
241
|
const {
|
|
136
242
|
timeout: timeoutMs = 2e3,
|
|
137
243
|
throwOnError = false,
|
|
138
|
-
onFallback
|
|
244
|
+
onFallback,
|
|
245
|
+
onReady
|
|
139
246
|
} = options;
|
|
140
247
|
if (!window.ReactNativeWebView) {
|
|
141
248
|
console.warn("[WebViewBridge] Not in a WebView environment");
|
|
@@ -148,62 +255,74 @@ var linkNativeMethod = (options = {
|
|
|
148
255
|
return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
|
|
149
256
|
};
|
|
150
257
|
const target = bridgeMethods.reduce(
|
|
151
|
-
(acc,
|
|
258
|
+
(acc, methodName) => {
|
|
152
259
|
return {
|
|
153
260
|
...acc,
|
|
154
|
-
[
|
|
155
|
-
|
|
261
|
+
[methodName]: createNativeMethod(
|
|
262
|
+
methodName,
|
|
156
263
|
timeoutMs,
|
|
157
|
-
willMethodThrowOnError(
|
|
264
|
+
willMethodThrowOnError(methodName)
|
|
158
265
|
)
|
|
159
266
|
};
|
|
160
267
|
},
|
|
161
|
-
{
|
|
162
|
-
isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
|
|
163
|
-
isNativeMethodAvailable(method) {
|
|
164
|
-
return typeof method === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(method);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
268
|
+
{}
|
|
167
269
|
);
|
|
168
270
|
const loose = new Proxy(target, {
|
|
169
|
-
get: (target2,
|
|
170
|
-
if (
|
|
171
|
-
|
|
271
|
+
get: (target2, methodName) => {
|
|
272
|
+
if (methodName in target2 && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
|
|
273
|
+
methodName
|
|
172
274
|
)) {
|
|
173
|
-
return target2[
|
|
275
|
+
return target2[methodName];
|
|
174
276
|
}
|
|
175
277
|
return createNativeMethod(
|
|
176
|
-
|
|
278
|
+
methodName,
|
|
177
279
|
timeoutMs,
|
|
178
|
-
willMethodThrowOnError(
|
|
280
|
+
willMethodThrowOnError(methodName)
|
|
179
281
|
);
|
|
180
282
|
}
|
|
181
283
|
});
|
|
182
|
-
Object.assign(target, {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
284
|
+
Object.assign(target, {
|
|
285
|
+
loose,
|
|
286
|
+
store: linkBridgeStore(target),
|
|
287
|
+
isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
|
|
288
|
+
isNativeMethodAvailable(methodName) {
|
|
289
|
+
return typeof methodName === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(methodName);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
const proxy = new Proxy(target, {
|
|
293
|
+
get: (target2, methodName) => {
|
|
294
|
+
if (methodName in target2) {
|
|
295
|
+
return target2[methodName];
|
|
187
296
|
}
|
|
188
297
|
window.ReactNativeWebView?.postMessage(
|
|
189
298
|
JSON.stringify({
|
|
190
299
|
type: "fallback",
|
|
191
300
|
body: {
|
|
192
|
-
method
|
|
301
|
+
method: methodName
|
|
193
302
|
}
|
|
194
303
|
})
|
|
195
304
|
);
|
|
196
|
-
onFallback?.(
|
|
197
|
-
if (willMethodThrowOnError(
|
|
198
|
-
return () => Promise.reject(new MethodNotFoundError(
|
|
305
|
+
onFallback?.(methodName);
|
|
306
|
+
if (willMethodThrowOnError(methodName)) {
|
|
307
|
+
return () => Promise.reject(new MethodNotFoundError(methodName));
|
|
199
308
|
} else {
|
|
200
309
|
console.warn(
|
|
201
|
-
`[WebViewBridge] ${
|
|
310
|
+
`[WebViewBridge] ${methodName} is not defined, using fallback.`
|
|
202
311
|
);
|
|
203
312
|
}
|
|
204
313
|
return () => Promise.resolve();
|
|
205
314
|
}
|
|
206
315
|
});
|
|
316
|
+
onReady?.(proxy);
|
|
317
|
+
return proxy;
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/linkNativeMethod.ts
|
|
321
|
+
var linkNativeMethod = (options = {
|
|
322
|
+
timeout: 2e3,
|
|
323
|
+
throwOnError: false
|
|
324
|
+
}) => {
|
|
325
|
+
return linkBridge(options);
|
|
207
326
|
};
|
|
208
327
|
|
|
209
328
|
// src/registerWebMethod.ts
|
|
@@ -257,6 +376,7 @@ var registerWebMethod = (bridge) => {
|
|
|
257
376
|
0 && (module.exports = {
|
|
258
377
|
MethodNotFoundError,
|
|
259
378
|
NativeMethodError,
|
|
379
|
+
linkBridge,
|
|
260
380
|
linkNativeMethod,
|
|
261
381
|
registerWebMethod
|
|
262
382
|
});
|
package/dist/module/index.mjs
CHANGED
|
@@ -28,10 +28,10 @@ var createEvents = () => ({
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
var createResolver = (emitter2,
|
|
31
|
+
var createResolver = (emitter2, methodName, eventId, evaluate, failHandler = false) => {
|
|
32
32
|
return new Promise((resolve, reject) => {
|
|
33
33
|
const unbind = emitter2.on(
|
|
34
|
-
`${
|
|
34
|
+
`${methodName}-${eventId}`,
|
|
35
35
|
(data, throwOccurred) => {
|
|
36
36
|
unbind();
|
|
37
37
|
if (throwOccurred) {
|
|
@@ -60,6 +60,63 @@ var createRandomId = (size = ID_LENGTH) => {
|
|
|
60
60
|
return randomValues.join("");
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
// ../../shared/util/src/equals.ts
|
|
64
|
+
var equals = (a, b) => {
|
|
65
|
+
if (a === b) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
69
|
+
const arrA = Array.isArray(a);
|
|
70
|
+
const arrB = Array.isArray(b);
|
|
71
|
+
let i;
|
|
72
|
+
let length;
|
|
73
|
+
let key;
|
|
74
|
+
if (arrA && arrB) {
|
|
75
|
+
length = a.length;
|
|
76
|
+
if (length !== b.length) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
for (i = length; i-- !== 0; ) {
|
|
80
|
+
if (!equals(a[i], b[i])) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
if (arrA !== arrB) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const keys = Object.keys(a);
|
|
90
|
+
length = keys.length;
|
|
91
|
+
if (length !== Object.keys(b).length) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
for (i = length; i-- !== 0; ) {
|
|
95
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (i = length; i-- !== 0; ) {
|
|
100
|
+
key = keys[i];
|
|
101
|
+
if (!equals(a[key], b[key])) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return a !== a && b !== b;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// ../../shared/util/src/removeUndefinedKeys.tsx
|
|
111
|
+
var removeUndefinedKeys = (obj) => {
|
|
112
|
+
Object.keys(obj).forEach((key) => {
|
|
113
|
+
if (obj[key] === void 0) {
|
|
114
|
+
delete obj[key];
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return obj;
|
|
118
|
+
};
|
|
119
|
+
|
|
63
120
|
// ../../shared/util/src/timeout.ts
|
|
64
121
|
var timeout = (ms, throwOnError = true) => {
|
|
65
122
|
return new Promise((resolve, reject) => {
|
|
@@ -73,40 +130,89 @@ var timeout = (ms, throwOnError = true) => {
|
|
|
73
130
|
});
|
|
74
131
|
};
|
|
75
132
|
|
|
76
|
-
// src/
|
|
133
|
+
// src/emitter.ts
|
|
77
134
|
var emitter = createEvents();
|
|
78
|
-
|
|
135
|
+
|
|
136
|
+
// src/linkBridgeStore.ts
|
|
137
|
+
var linkBridgeStore = (initialState = {}) => {
|
|
138
|
+
if (!window.ReactNativeWebView) {
|
|
139
|
+
console.warn("[WebViewBridge] Not in a WebView environment");
|
|
140
|
+
}
|
|
141
|
+
if (!window.nativeEmitter) {
|
|
142
|
+
window.nativeEmitter = emitter;
|
|
143
|
+
}
|
|
144
|
+
const getState = () => state;
|
|
145
|
+
const setState = (newState) => {
|
|
146
|
+
const _newState = {
|
|
147
|
+
...state,
|
|
148
|
+
...removeUndefinedKeys(newState)
|
|
149
|
+
};
|
|
150
|
+
if (equals(state, _newState)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const prevState = state;
|
|
154
|
+
state = _newState;
|
|
155
|
+
emitChange(state, prevState);
|
|
156
|
+
};
|
|
157
|
+
emitter.on("bridgeStateChange", (data) => {
|
|
158
|
+
setState(data);
|
|
159
|
+
});
|
|
160
|
+
window.ReactNativeWebView?.postMessage(
|
|
161
|
+
JSON.stringify({
|
|
162
|
+
type: "getBridgeState"
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
let state = { ...initialState, ...window.__bridgeInitialState__ };
|
|
166
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
167
|
+
const emitChange = (newState, prevState) => {
|
|
168
|
+
for (const listener of listeners) {
|
|
169
|
+
listener(newState, prevState);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const subscribe = (listener) => {
|
|
173
|
+
listeners.add(listener);
|
|
174
|
+
return () => listeners.delete(listener);
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
getState,
|
|
178
|
+
subscribe
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// src/linkBridge.ts
|
|
183
|
+
var createNativeMethod = (methodName, timeoutMs, throwOnError) => (...args) => {
|
|
79
184
|
const eventId = createRandomId();
|
|
80
185
|
return Promise.race([
|
|
81
186
|
createResolver(
|
|
82
187
|
emitter,
|
|
83
|
-
|
|
188
|
+
methodName,
|
|
84
189
|
eventId,
|
|
85
190
|
() => {
|
|
86
191
|
window.ReactNativeWebView?.postMessage(
|
|
87
192
|
JSON.stringify({
|
|
88
193
|
type: "bridge",
|
|
89
194
|
body: {
|
|
90
|
-
method,
|
|
195
|
+
method: methodName,
|
|
91
196
|
eventId,
|
|
92
197
|
args
|
|
93
198
|
}
|
|
94
199
|
})
|
|
95
200
|
);
|
|
96
201
|
},
|
|
97
|
-
throwOnError && new NativeMethodError(
|
|
202
|
+
throwOnError && new NativeMethodError(methodName)
|
|
98
203
|
),
|
|
99
204
|
timeout(timeoutMs, throwOnError)
|
|
100
205
|
]);
|
|
101
206
|
};
|
|
102
|
-
var
|
|
207
|
+
var linkBridge = (options = {
|
|
103
208
|
timeout: 2e3,
|
|
104
209
|
throwOnError: false
|
|
105
210
|
}) => {
|
|
106
211
|
const {
|
|
107
212
|
timeout: timeoutMs = 2e3,
|
|
108
213
|
throwOnError = false,
|
|
109
|
-
onFallback
|
|
214
|
+
onFallback,
|
|
215
|
+
onReady
|
|
110
216
|
} = options;
|
|
111
217
|
if (!window.ReactNativeWebView) {
|
|
112
218
|
console.warn("[WebViewBridge] Not in a WebView environment");
|
|
@@ -119,62 +225,74 @@ var linkNativeMethod = (options = {
|
|
|
119
225
|
return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
|
|
120
226
|
};
|
|
121
227
|
const target = bridgeMethods.reduce(
|
|
122
|
-
(acc,
|
|
228
|
+
(acc, methodName) => {
|
|
123
229
|
return {
|
|
124
230
|
...acc,
|
|
125
|
-
[
|
|
126
|
-
|
|
231
|
+
[methodName]: createNativeMethod(
|
|
232
|
+
methodName,
|
|
127
233
|
timeoutMs,
|
|
128
|
-
willMethodThrowOnError(
|
|
234
|
+
willMethodThrowOnError(methodName)
|
|
129
235
|
)
|
|
130
236
|
};
|
|
131
237
|
},
|
|
132
|
-
{
|
|
133
|
-
isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
|
|
134
|
-
isNativeMethodAvailable(method) {
|
|
135
|
-
return typeof method === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(method);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
238
|
+
{}
|
|
138
239
|
);
|
|
139
240
|
const loose = new Proxy(target, {
|
|
140
|
-
get: (target2,
|
|
141
|
-
if (
|
|
142
|
-
|
|
241
|
+
get: (target2, methodName) => {
|
|
242
|
+
if (methodName in target2 && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
|
|
243
|
+
methodName
|
|
143
244
|
)) {
|
|
144
|
-
return target2[
|
|
245
|
+
return target2[methodName];
|
|
145
246
|
}
|
|
146
247
|
return createNativeMethod(
|
|
147
|
-
|
|
248
|
+
methodName,
|
|
148
249
|
timeoutMs,
|
|
149
|
-
willMethodThrowOnError(
|
|
250
|
+
willMethodThrowOnError(methodName)
|
|
150
251
|
);
|
|
151
252
|
}
|
|
152
253
|
});
|
|
153
|
-
Object.assign(target, {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
254
|
+
Object.assign(target, {
|
|
255
|
+
loose,
|
|
256
|
+
store: linkBridgeStore(target),
|
|
257
|
+
isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
|
|
258
|
+
isNativeMethodAvailable(methodName) {
|
|
259
|
+
return typeof methodName === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(methodName);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const proxy = new Proxy(target, {
|
|
263
|
+
get: (target2, methodName) => {
|
|
264
|
+
if (methodName in target2) {
|
|
265
|
+
return target2[methodName];
|
|
158
266
|
}
|
|
159
267
|
window.ReactNativeWebView?.postMessage(
|
|
160
268
|
JSON.stringify({
|
|
161
269
|
type: "fallback",
|
|
162
270
|
body: {
|
|
163
|
-
method
|
|
271
|
+
method: methodName
|
|
164
272
|
}
|
|
165
273
|
})
|
|
166
274
|
);
|
|
167
|
-
onFallback?.(
|
|
168
|
-
if (willMethodThrowOnError(
|
|
169
|
-
return () => Promise.reject(new MethodNotFoundError(
|
|
275
|
+
onFallback?.(methodName);
|
|
276
|
+
if (willMethodThrowOnError(methodName)) {
|
|
277
|
+
return () => Promise.reject(new MethodNotFoundError(methodName));
|
|
170
278
|
} else {
|
|
171
279
|
console.warn(
|
|
172
|
-
`[WebViewBridge] ${
|
|
280
|
+
`[WebViewBridge] ${methodName} is not defined, using fallback.`
|
|
173
281
|
);
|
|
174
282
|
}
|
|
175
283
|
return () => Promise.resolve();
|
|
176
284
|
}
|
|
177
285
|
});
|
|
286
|
+
onReady?.(proxy);
|
|
287
|
+
return proxy;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// src/linkNativeMethod.ts
|
|
291
|
+
var linkNativeMethod = (options = {
|
|
292
|
+
timeout: 2e3,
|
|
293
|
+
throwOnError: false
|
|
294
|
+
}) => {
|
|
295
|
+
return linkBridge(options);
|
|
178
296
|
};
|
|
179
297
|
|
|
180
298
|
// src/registerWebMethod.ts
|
|
@@ -227,6 +345,7 @@ var registerWebMethod = (bridge) => {
|
|
|
227
345
|
export {
|
|
228
346
|
MethodNotFoundError,
|
|
229
347
|
NativeMethodError,
|
|
348
|
+
linkBridge,
|
|
230
349
|
linkNativeMethod,
|
|
231
350
|
registerWebMethod
|
|
232
351
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const emitter: import("../../../shared/util/src").EventEmitter<import("../../../shared/util/src").DefaultEvents>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Bridge, BridgeStore, ExcludePrimitive, ExtractStore } from "../../../shared/util/src/types";
|
|
2
|
+
import { LinkBridge } from "./types";
|
|
3
|
+
export interface LinkBridgeOptions<T extends BridgeStore<T extends Bridge ? T : any>> {
|
|
4
|
+
timeout?: number;
|
|
5
|
+
throwOnError?: boolean | (keyof ExtractStore<T>)[] | string[];
|
|
6
|
+
onFallback?: (methodName: string) => void;
|
|
7
|
+
onReady?: (method: LinkBridge<ExcludePrimitive<ExtractStore<T>>, Omit<T, "setState">>) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const linkBridge: <T extends BridgeStore<T extends Bridge ? T : any>>(options?: LinkBridgeOptions<T>) => LinkBridge<ExcludePrimitive<ExtractStore<T>>, Omit<T, "setState">>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Bridge, BridgeStore, OnlyJSON } from "../../../shared/util/src/types";
|
|
2
|
+
export type Store<BridgeObject extends Bridge> = ({ get, set, }: {
|
|
3
|
+
get: () => BridgeObject;
|
|
4
|
+
set: (newState: Partial<OnlyJSON<BridgeObject>>) => void;
|
|
5
|
+
}) => BridgeObject;
|
|
6
|
+
export declare const linkBridgeStore: <T extends BridgeStore<T extends Bridge ? T : any>>(initialState?: Partial<T>) => Omit<T, "setState">;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Bridge,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export declare const linkNativeMethod: <
|
|
1
|
+
import type { Bridge, BridgeStore, ExcludePrimitive, ExtractStore } from "../../../shared/util/src/types";
|
|
2
|
+
import { LinkBridgeOptions } from "./linkBridge";
|
|
3
|
+
import { LinkBridge } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use `linkBridge` instead. It's just renamed to `linkBridge`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const linkNativeMethod: <T extends BridgeStore<T extends Bridge ? T : any>>(options?: LinkBridgeOptions<T>) => LinkBridge<ExcludePrimitive<ExtractStore<T>>, Omit<T, "setState">>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const registerWebMethod: <BridgeObject extends
|
|
1
|
+
import type { WebBridge } from "./types";
|
|
2
|
+
export declare const registerWebMethod: <BridgeObject extends WebBridge>(bridge: BridgeObject) => BridgeObject;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
1
|
+
import { AsyncFunction } from "../../../../shared/util/src/types";
|
|
2
|
+
export type WebBridge = Record<string, AsyncFunction>;
|
|
3
|
+
export type LinkBridge<T, U> = {
|
|
4
4
|
isWebViewBridgeAvailable: boolean;
|
|
5
5
|
isNativeMethodAvailable(method: keyof T): boolean;
|
|
6
6
|
isNativeMethodAvailable(method: string): boolean;
|
|
7
|
+
store: U;
|
|
7
8
|
loose: {
|
|
8
9
|
[K in keyof T]: (...args: any[]) => Promise<any>;
|
|
9
10
|
} & {
|
|
@@ -12,5 +12,5 @@ export interface EventEmitter<Events extends EventsMap = DefaultEvents> {
|
|
|
12
12
|
on<K extends keyof Events>(this: this, event: K, cb: Events[K]): () => void;
|
|
13
13
|
}
|
|
14
14
|
export declare const createEvents: <Events extends EventsMap = DefaultEvents>() => EventEmitter<Events>;
|
|
15
|
-
export declare const createResolver: (emitter: EventEmitter<DefaultEvents>,
|
|
15
|
+
export declare const createResolver: (emitter: EventEmitter<DefaultEvents>, methodName: string, eventId: string, evaluate: () => void, failHandler?: Error | false) => Promise<unknown>;
|
|
16
16
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const equals: (a: any, b: any) => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const removeUndefinedKeys: (obj: Record<string, any>) => Record<string, any>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type AsyncFunction = (...args: any[]) => Promise<any>;
|
|
2
|
+
export type Primitive = string | number | boolean | null | undefined;
|
|
3
|
+
export type RawJSON = Primitive | {
|
|
4
|
+
[key: string]: RawJSON;
|
|
5
|
+
} | RawJSONArray;
|
|
6
|
+
interface RawJSONArray extends Array<RawJSON> {
|
|
7
|
+
}
|
|
8
|
+
export type Bridge = Record<string, AsyncFunction | RawJSON>;
|
|
9
|
+
export type BridgeStore<T extends Bridge> = {
|
|
10
|
+
getState: () => T;
|
|
11
|
+
setState: (newState: Partial<OnlyJSON<T>>) => void;
|
|
12
|
+
subscribe: (listener: (newState: T, prevState: T) => void) => () => void;
|
|
13
|
+
};
|
|
14
|
+
export type ExtractStore<S> = S extends {
|
|
15
|
+
getState: () => infer T;
|
|
16
|
+
} ? T : never;
|
|
17
|
+
export type OnlyJSON<T> = {
|
|
18
|
+
[P in keyof T as T[P] extends RawJSON ? P : never]: T[P];
|
|
19
|
+
};
|
|
20
|
+
export type ExcludePrimitive<T> = {
|
|
21
|
+
[P in keyof T as T[P] extends RawJSON ? never : P]: T[P];
|
|
22
|
+
};
|
|
23
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webview-bridge/web",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0-nightly.0",
|
|
5
5
|
"description": "Fully Type-Safe Integration for React Native WebView and Web",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"esbuild": "^0.19.4"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"build": "node esbuild.config.js &&
|
|
37
|
+
"build": "node esbuild.config.js && tspc --emitDeclarationOnly",
|
|
38
38
|
"test:type": "tsc --noEmit"
|
|
39
39
|
}
|
|
40
40
|
}
|