@webview-bridge/web 1.5.0 → 1.5.1-rc.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.
@@ -1,8 +1,25 @@
1
1
  "use strict";
2
2
  var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6
23
  var __export = (target, all) => {
7
24
  for (var name in all)
8
25
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,6 +33,30 @@ var __copyProps = (to, from, except, desc) => {
16
33
  return to;
17
34
  };
18
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
+ var __publicField = (obj, key, value) => {
37
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
38
+ return value;
39
+ };
40
+ var __async = (__this, __arguments, generator) => {
41
+ return new Promise((resolve, reject) => {
42
+ var fulfilled = (value) => {
43
+ try {
44
+ step(generator.next(value));
45
+ } catch (e) {
46
+ reject(e);
47
+ }
48
+ };
49
+ var rejected = (value) => {
50
+ try {
51
+ step(generator.throw(value));
52
+ } catch (e) {
53
+ reject(e);
54
+ }
55
+ };
56
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
57
+ step((generator = generator.apply(__this, __arguments)).next());
58
+ });
59
+ };
19
60
 
20
61
  // src/index.ts
21
62
  var src_exports = {};
@@ -52,14 +93,16 @@ var createEvents = () => ({
52
93
  }
53
94
  },
54
95
  on(event, cb) {
55
- this.events[event]?.push(cb) || (this.events[event] = [cb]);
96
+ var _a;
97
+ ((_a = this.events[event]) == null ? void 0 : _a.push(cb)) || (this.events[event] = [cb]);
56
98
  return () => {
57
- this.events[event] = this.events[event]?.filter((i) => cb !== i);
99
+ var _a2;
100
+ this.events[event] = (_a2 = this.events[event]) == null ? void 0 : _a2.filter((i) => cb !== i);
58
101
  };
59
102
  }
60
103
  });
61
104
  var createResolver = ({
62
- emitter: emitter2,
105
+ emitter,
63
106
  evaluate,
64
107
  eventId,
65
108
  failHandler = false,
@@ -67,13 +110,13 @@ var createResolver = ({
67
110
  onFallback
68
111
  }) => {
69
112
  return new Promise((resolve, reject) => {
70
- const unbind = emitter2.on(
113
+ const unbind = emitter.on(
71
114
  `${methodName}-${eventId}`,
72
115
  (data, throwOccurred) => {
73
116
  unbind();
74
117
  if (throwOccurred) {
75
118
  if (failHandler instanceof Error) {
76
- onFallback?.();
119
+ onFallback == null ? void 0 : onFallback();
77
120
  reject(failHandler);
78
121
  } else {
79
122
  resolve(void 0);
@@ -172,23 +215,11 @@ var timeout = (ms, throwOnError = true) => {
172
215
  });
173
216
  };
174
217
 
175
- // src/internal/emitter.ts
176
- var emitter = createEvents();
177
-
178
218
  // src/internal/linkBridgeStore.ts
179
- var linkBridgeStore = (initialState = {}) => {
180
- if (!window.ReactNativeWebView) {
181
- console.warn("[WebViewBridge] Not in a WebView environment");
182
- }
183
- if (!window.nativeEmitter) {
184
- window.nativeEmitter = emitter;
185
- }
219
+ var linkBridgeStore = (emitter, initialState = {}, nativeInitialState = {}) => {
186
220
  const getState = () => state;
187
221
  const setState = (newState) => {
188
- const _newState = {
189
- ...state,
190
- ...removeUndefinedKeys(newState)
191
- };
222
+ const _newState = __spreadValues(__spreadValues({}, state), removeUndefinedKeys(newState));
192
223
  if (equals(state, _newState)) {
193
224
  return;
194
225
  }
@@ -199,21 +230,7 @@ var linkBridgeStore = (initialState = {}) => {
199
230
  emitter.on("bridgeStateChange", (data) => {
200
231
  setState(data);
201
232
  });
202
- document.addEventListener("visibilitychange", () => {
203
- if (document.visibilityState === "visible") {
204
- window.ReactNativeWebView?.postMessage(
205
- JSON.stringify({
206
- type: "getBridgeState"
207
- })
208
- );
209
- }
210
- });
211
- window.ReactNativeWebView?.postMessage(
212
- JSON.stringify({
213
- type: "getBridgeState"
214
- })
215
- );
216
- let state = { ...initialState, ...window.__bridgeInitialState__ };
233
+ let state = __spreadValues(__spreadValues({}, initialState), nativeInitialState);
217
234
  const listeners = /* @__PURE__ */ new Set();
218
235
  const emitChange = (newState, prevState) => {
219
236
  for (const listener of listeners) {
@@ -230,45 +247,160 @@ var linkBridgeStore = (initialState = {}) => {
230
247
  };
231
248
  };
232
249
 
233
- // src/linkBridge.ts
234
- var createNativeMethod = ({
235
- methodName,
236
- throwOnError,
237
- timeoutMs,
238
- onFallback
239
- }) => (...args) => {
240
- const eventId = createRandomId();
241
- return Promise.race(
242
- [
243
- createResolver({
244
- emitter,
245
- methodName,
246
- eventId,
247
- evaluate: () => {
248
- window.ReactNativeWebView?.postMessage(
249
- JSON.stringify({
250
- type: "bridge",
251
- body: {
250
+ // src/internal/bridgeInstance.ts
251
+ var BridgeInstance = class {
252
+ constructor(emitter, bridgeMethods, options) {
253
+ this.emitter = emitter;
254
+ this.bridgeMethods = bridgeMethods;
255
+ this.options = options;
256
+ __publicField(this, "defaultTimeoutMs", 2e3);
257
+ __publicField(this, "$proxy");
258
+ this.$proxy = this.hydrate(bridgeMethods);
259
+ }
260
+ postMessage(type, body) {
261
+ var _a;
262
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
263
+ JSON.stringify(
264
+ body ? {
265
+ type,
266
+ body
267
+ } : {
268
+ type
269
+ }
270
+ )
271
+ );
272
+ }
273
+ createNativeMethod(methodName, throwOnError, timeoutMs, onFallback) {
274
+ return (...args) => {
275
+ const eventId = createRandomId();
276
+ return Promise.race(
277
+ [
278
+ createResolver({
279
+ emitter: this.emitter,
280
+ methodName,
281
+ eventId,
282
+ evaluate: () => {
283
+ this.postMessage("bridge", {
252
284
  method: methodName,
253
285
  eventId,
254
286
  args
255
- }
256
- })
287
+ });
288
+ },
289
+ onFallback: () => {
290
+ onFallback == null ? void 0 : onFallback(methodName, args);
291
+ },
292
+ failHandler: throwOnError && new NativeMethodError(methodName)
293
+ }),
294
+ timeoutMs > 0 && timeout(timeoutMs, throwOnError)
295
+ ].filter(Boolean)
296
+ );
297
+ };
298
+ }
299
+ willMethodThrowOnError(methodName) {
300
+ const { throwOnError } = this.options;
301
+ return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
302
+ }
303
+ createLoose(initialState) {
304
+ const { timeout: timeoutMs = this.defaultTimeoutMs, onFallback } = this.options;
305
+ return new Proxy(initialState, {
306
+ get: (target, methodName) => {
307
+ if (methodName in target && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
308
+ methodName
309
+ )) {
310
+ return target[methodName];
311
+ }
312
+ return this.createNativeMethod(
313
+ methodName,
314
+ this.willMethodThrowOnError(methodName),
315
+ timeoutMs,
316
+ onFallback
317
+ );
318
+ }
319
+ });
320
+ }
321
+ hydrate(bridgeMethods, nativeInitialState = {}) {
322
+ var _a;
323
+ const {
324
+ timeout: timeoutMs = this.defaultTimeoutMs,
325
+ onFallback,
326
+ onReady
327
+ } = this.options;
328
+ const initialState = bridgeMethods.reduce(
329
+ (acc, methodName) => {
330
+ return __spreadProps(__spreadValues({}, acc), {
331
+ [methodName]: this.createNativeMethod(
332
+ methodName,
333
+ this.willMethodThrowOnError(methodName),
334
+ timeoutMs,
335
+ onFallback
336
+ )
337
+ });
338
+ },
339
+ {}
340
+ );
341
+ const loose = this.createLoose(initialState);
342
+ const store = linkBridgeStore(
343
+ this.emitter,
344
+ initialState,
345
+ nativeInitialState
346
+ );
347
+ Object.assign(initialState, {
348
+ loose,
349
+ store,
350
+ isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
351
+ isNativeMethodAvailable(methodName) {
352
+ return typeof methodName === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(methodName);
353
+ },
354
+ addEventListener: (eventName, listener) => {
355
+ return this.emitter.on(`postMessage/${String(eventName)}`, listener);
356
+ }
357
+ });
358
+ document.addEventListener("visibilitychange", () => {
359
+ if (document.visibilityState === "visible") {
360
+ this.postMessage("getBridgeState");
361
+ }
362
+ });
363
+ this.postMessage("getBridgeState");
364
+ const proxy = new Proxy(initialState, {
365
+ get: (target, methodName) => {
366
+ if (methodName in target) {
367
+ return target[methodName];
368
+ }
369
+ this.postMessage("fallback", {
370
+ method: methodName
371
+ });
372
+ if (this.willMethodThrowOnError(methodName)) {
373
+ return (...args) => {
374
+ onFallback == null ? void 0 : onFallback(methodName, args);
375
+ return Promise.reject(new MethodNotFoundError(methodName));
376
+ };
377
+ } else {
378
+ console.warn(
379
+ `[WebViewBridge] ${methodName} is not defined, using fallback.`
257
380
  );
258
- },
259
- onFallback: () => {
260
- onFallback?.(methodName, args);
261
- },
262
- failHandler: throwOnError && new NativeMethodError(methodName)
263
- }),
264
- timeoutMs > 0 && timeout(timeoutMs, throwOnError)
265
- ].filter(Boolean)
266
- );
381
+ }
382
+ return () => Promise.resolve();
383
+ }
384
+ });
385
+ for (const [eventName, ...args] of (_a = window.nativeBatchedEvents) != null ? _a : []) {
386
+ this.emitter.emit(eventName, ...args);
387
+ }
388
+ window.nativeBatchedEvents = [];
389
+ onReady == null ? void 0 : onReady(proxy);
390
+ this.$proxy = proxy;
391
+ return proxy;
392
+ }
393
+ get proxy() {
394
+ return this.$proxy;
395
+ }
267
396
  };
397
+
398
+ // src/linkBridge.ts
268
399
  var linkBridge = (options = {
269
400
  timeout: 2e3,
270
401
  throwOnError: false
271
402
  }) => {
403
+ var _a;
272
404
  if (typeof window === "undefined") {
273
405
  return {
274
406
  store: {
@@ -277,94 +409,23 @@ var linkBridge = (options = {
277
409
  }
278
410
  };
279
411
  }
280
- const {
281
- timeout: timeoutMs = 2e3,
282
- throwOnError = false,
283
- onFallback,
284
- onReady
285
- } = options;
286
412
  if (!window.ReactNativeWebView) {
287
413
  console.warn("[WebViewBridge] Not in a WebView environment");
288
414
  }
289
- const bridgeMethods = window.__bridgeMethods__ ?? [];
415
+ const emitter = createEvents();
290
416
  if (!window.nativeEmitter) {
291
417
  window.nativeEmitter = emitter;
292
418
  }
293
- const willMethodThrowOnError = (methodName) => {
294
- return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
295
- };
296
- const target = bridgeMethods.reduce(
297
- (acc, methodName) => {
298
- return {
299
- ...acc,
300
- [methodName]: createNativeMethod({
301
- methodName,
302
- timeoutMs,
303
- throwOnError: willMethodThrowOnError(methodName),
304
- onFallback
305
- })
306
- };
307
- },
308
- {}
309
- );
310
- const loose = new Proxy(target, {
311
- get: (target2, methodName) => {
312
- if (methodName in target2 && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
313
- methodName
314
- )) {
315
- return target2[methodName];
316
- }
317
- return createNativeMethod({
318
- methodName,
319
- timeoutMs,
320
- throwOnError: willMethodThrowOnError(methodName),
321
- onFallback
322
- });
323
- }
324
- });
325
- Object.assign(target, {
326
- loose,
327
- store: linkBridgeStore(target),
328
- isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
329
- isNativeMethodAvailable(methodName) {
330
- return typeof methodName === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(methodName);
331
- },
332
- addEventListener: (eventName, listener) => {
333
- return emitter.on(`postMessage/${String(eventName)}`, listener);
334
- }
335
- });
336
- const proxy = new Proxy(target, {
337
- get: (target2, methodName) => {
338
- if (methodName in target2) {
339
- return target2[methodName];
340
- }
341
- window.ReactNativeWebView?.postMessage(
342
- JSON.stringify({
343
- type: "fallback",
344
- body: {
345
- method: methodName
346
- }
347
- })
348
- );
349
- if (willMethodThrowOnError(methodName)) {
350
- return (...args) => {
351
- onFallback?.(methodName, args);
352
- Promise.reject(new MethodNotFoundError(methodName));
353
- };
354
- } else {
355
- console.warn(
356
- `[WebViewBridge] ${methodName} is not defined, using fallback.`
357
- );
358
- }
359
- return () => Promise.resolve();
360
- }
361
- });
362
- for (const [eventName, ...args] of window.nativeBatchedEvents ?? []) {
363
- emitter.emit(eventName, ...args);
419
+ const bridgeMethods = (_a = window.__bridgeMethods__) != null ? _a : [];
420
+ const instance = new BridgeInstance(emitter, bridgeMethods, options);
421
+ if (bridgeMethods.length === 0) {
422
+ const unsubscribe = emitter.on("hydrate", ({ bridgeMethods: bridgeMethods2 }) => {
423
+ instance.hydrate(bridgeMethods2);
424
+ unsubscribe();
425
+ });
364
426
  }
365
- window.nativeBatchedEvents = [];
366
- onReady?.(proxy);
367
- return proxy;
427
+ instance.hydrate(bridgeMethods);
428
+ return instance.proxy;
368
429
  };
369
430
 
370
431
  // src/linkNativeMethod.ts
@@ -383,31 +444,33 @@ var registerWebMethod = (bridge) => {
383
444
  }
384
445
  const bridgeEntries = Object.entries(bridge);
385
446
  const bridgeNames = Object.keys(bridge);
386
- const emitter2 = createEvents();
387
- window.webEmitter = emitter2;
447
+ const emitter = createEvents();
448
+ window.webEmitter = emitter;
388
449
  for (const [funcName, func] of bridgeEntries) {
389
- const $func = async (eventId, args) => {
450
+ const $func = (eventId, args) => __async(void 0, null, function* () {
451
+ var _a, _b;
390
452
  try {
391
- const value = await func(...args);
392
- window.ReactNativeWebView?.postMessage(
453
+ const value = yield func(...args);
454
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
393
455
  JSON.stringify({
394
456
  type: "webMethodResponse",
395
457
  body: { funcName, eventId, value }
396
458
  })
397
459
  );
398
460
  } catch (e) {
399
- window.ReactNativeWebView?.postMessage(
461
+ (_b = window.ReactNativeWebView) == null ? void 0 : _b.postMessage(
400
462
  JSON.stringify({
401
463
  type: "webMethodError",
402
464
  body: { funcName, eventId, error: JSON.stringify(e) }
403
465
  })
404
466
  );
405
467
  }
406
- };
407
- emitter2.on(funcName, $func);
468
+ });
469
+ emitter.on(funcName, $func);
408
470
  }
409
471
  const register = () => {
410
- window.ReactNativeWebView?.postMessage(
472
+ var _a;
473
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
411
474
  JSON.stringify({
412
475
  type: "registerWebMethod",
413
476
  body: { bridgeNames }
@@ -420,8 +483,9 @@ var registerWebMethod = (bridge) => {
420
483
  return bridge;
421
484
  }
422
485
  document.addEventListener("visibilitychange", () => {
486
+ var _a;
423
487
  if (document.visibilityState === "visible") {
424
- window.ReactNativeWebView?.postMessage(
488
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
425
489
  JSON.stringify({
426
490
  type: "registerWebMethod",
427
491
  body: { bridgeNames }
@@ -1,3 +1,47 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __publicField = (obj, key, value) => {
21
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
+ return value;
23
+ };
24
+ var __async = (__this, __arguments, generator) => {
25
+ return new Promise((resolve, reject) => {
26
+ var fulfilled = (value) => {
27
+ try {
28
+ step(generator.next(value));
29
+ } catch (e) {
30
+ reject(e);
31
+ }
32
+ };
33
+ var rejected = (value) => {
34
+ try {
35
+ step(generator.throw(value));
36
+ } catch (e) {
37
+ reject(e);
38
+ }
39
+ };
40
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
41
+ step((generator = generator.apply(__this, __arguments)).next());
42
+ });
43
+ };
44
+
1
45
  // src/error.ts
2
46
  var MethodNotFoundError = class extends Error {
3
47
  constructor(methodName) {
@@ -22,14 +66,16 @@ var createEvents = () => ({
22
66
  }
23
67
  },
24
68
  on(event, cb) {
25
- this.events[event]?.push(cb) || (this.events[event] = [cb]);
69
+ var _a;
70
+ ((_a = this.events[event]) == null ? void 0 : _a.push(cb)) || (this.events[event] = [cb]);
26
71
  return () => {
27
- this.events[event] = this.events[event]?.filter((i) => cb !== i);
72
+ var _a2;
73
+ this.events[event] = (_a2 = this.events[event]) == null ? void 0 : _a2.filter((i) => cb !== i);
28
74
  };
29
75
  }
30
76
  });
31
77
  var createResolver = ({
32
- emitter: emitter2,
78
+ emitter,
33
79
  evaluate,
34
80
  eventId,
35
81
  failHandler = false,
@@ -37,13 +83,13 @@ var createResolver = ({
37
83
  onFallback
38
84
  }) => {
39
85
  return new Promise((resolve, reject) => {
40
- const unbind = emitter2.on(
86
+ const unbind = emitter.on(
41
87
  `${methodName}-${eventId}`,
42
88
  (data, throwOccurred) => {
43
89
  unbind();
44
90
  if (throwOccurred) {
45
91
  if (failHandler instanceof Error) {
46
- onFallback?.();
92
+ onFallback == null ? void 0 : onFallback();
47
93
  reject(failHandler);
48
94
  } else {
49
95
  resolve(void 0);
@@ -142,23 +188,11 @@ var timeout = (ms, throwOnError = true) => {
142
188
  });
143
189
  };
144
190
 
145
- // src/internal/emitter.ts
146
- var emitter = createEvents();
147
-
148
191
  // src/internal/linkBridgeStore.ts
149
- var linkBridgeStore = (initialState = {}) => {
150
- if (!window.ReactNativeWebView) {
151
- console.warn("[WebViewBridge] Not in a WebView environment");
152
- }
153
- if (!window.nativeEmitter) {
154
- window.nativeEmitter = emitter;
155
- }
192
+ var linkBridgeStore = (emitter, initialState = {}, nativeInitialState = {}) => {
156
193
  const getState = () => state;
157
194
  const setState = (newState) => {
158
- const _newState = {
159
- ...state,
160
- ...removeUndefinedKeys(newState)
161
- };
195
+ const _newState = __spreadValues(__spreadValues({}, state), removeUndefinedKeys(newState));
162
196
  if (equals(state, _newState)) {
163
197
  return;
164
198
  }
@@ -169,21 +203,7 @@ var linkBridgeStore = (initialState = {}) => {
169
203
  emitter.on("bridgeStateChange", (data) => {
170
204
  setState(data);
171
205
  });
172
- document.addEventListener("visibilitychange", () => {
173
- if (document.visibilityState === "visible") {
174
- window.ReactNativeWebView?.postMessage(
175
- JSON.stringify({
176
- type: "getBridgeState"
177
- })
178
- );
179
- }
180
- });
181
- window.ReactNativeWebView?.postMessage(
182
- JSON.stringify({
183
- type: "getBridgeState"
184
- })
185
- );
186
- let state = { ...initialState, ...window.__bridgeInitialState__ };
206
+ let state = __spreadValues(__spreadValues({}, initialState), nativeInitialState);
187
207
  const listeners = /* @__PURE__ */ new Set();
188
208
  const emitChange = (newState, prevState) => {
189
209
  for (const listener of listeners) {
@@ -200,45 +220,160 @@ var linkBridgeStore = (initialState = {}) => {
200
220
  };
201
221
  };
202
222
 
203
- // src/linkBridge.ts
204
- var createNativeMethod = ({
205
- methodName,
206
- throwOnError,
207
- timeoutMs,
208
- onFallback
209
- }) => (...args) => {
210
- const eventId = createRandomId();
211
- return Promise.race(
212
- [
213
- createResolver({
214
- emitter,
215
- methodName,
216
- eventId,
217
- evaluate: () => {
218
- window.ReactNativeWebView?.postMessage(
219
- JSON.stringify({
220
- type: "bridge",
221
- body: {
223
+ // src/internal/bridgeInstance.ts
224
+ var BridgeInstance = class {
225
+ constructor(emitter, bridgeMethods, options) {
226
+ this.emitter = emitter;
227
+ this.bridgeMethods = bridgeMethods;
228
+ this.options = options;
229
+ __publicField(this, "defaultTimeoutMs", 2e3);
230
+ __publicField(this, "$proxy");
231
+ this.$proxy = this.hydrate(bridgeMethods);
232
+ }
233
+ postMessage(type, body) {
234
+ var _a;
235
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
236
+ JSON.stringify(
237
+ body ? {
238
+ type,
239
+ body
240
+ } : {
241
+ type
242
+ }
243
+ )
244
+ );
245
+ }
246
+ createNativeMethod(methodName, throwOnError, timeoutMs, onFallback) {
247
+ return (...args) => {
248
+ const eventId = createRandomId();
249
+ return Promise.race(
250
+ [
251
+ createResolver({
252
+ emitter: this.emitter,
253
+ methodName,
254
+ eventId,
255
+ evaluate: () => {
256
+ this.postMessage("bridge", {
222
257
  method: methodName,
223
258
  eventId,
224
259
  args
225
- }
226
- })
260
+ });
261
+ },
262
+ onFallback: () => {
263
+ onFallback == null ? void 0 : onFallback(methodName, args);
264
+ },
265
+ failHandler: throwOnError && new NativeMethodError(methodName)
266
+ }),
267
+ timeoutMs > 0 && timeout(timeoutMs, throwOnError)
268
+ ].filter(Boolean)
269
+ );
270
+ };
271
+ }
272
+ willMethodThrowOnError(methodName) {
273
+ const { throwOnError } = this.options;
274
+ return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
275
+ }
276
+ createLoose(initialState) {
277
+ const { timeout: timeoutMs = this.defaultTimeoutMs, onFallback } = this.options;
278
+ return new Proxy(initialState, {
279
+ get: (target, methodName) => {
280
+ if (methodName in target && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
281
+ methodName
282
+ )) {
283
+ return target[methodName];
284
+ }
285
+ return this.createNativeMethod(
286
+ methodName,
287
+ this.willMethodThrowOnError(methodName),
288
+ timeoutMs,
289
+ onFallback
290
+ );
291
+ }
292
+ });
293
+ }
294
+ hydrate(bridgeMethods, nativeInitialState = {}) {
295
+ var _a;
296
+ const {
297
+ timeout: timeoutMs = this.defaultTimeoutMs,
298
+ onFallback,
299
+ onReady
300
+ } = this.options;
301
+ const initialState = bridgeMethods.reduce(
302
+ (acc, methodName) => {
303
+ return __spreadProps(__spreadValues({}, acc), {
304
+ [methodName]: this.createNativeMethod(
305
+ methodName,
306
+ this.willMethodThrowOnError(methodName),
307
+ timeoutMs,
308
+ onFallback
309
+ )
310
+ });
311
+ },
312
+ {}
313
+ );
314
+ const loose = this.createLoose(initialState);
315
+ const store = linkBridgeStore(
316
+ this.emitter,
317
+ initialState,
318
+ nativeInitialState
319
+ );
320
+ Object.assign(initialState, {
321
+ loose,
322
+ store,
323
+ isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
324
+ isNativeMethodAvailable(methodName) {
325
+ return typeof methodName === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(methodName);
326
+ },
327
+ addEventListener: (eventName, listener) => {
328
+ return this.emitter.on(`postMessage/${String(eventName)}`, listener);
329
+ }
330
+ });
331
+ document.addEventListener("visibilitychange", () => {
332
+ if (document.visibilityState === "visible") {
333
+ this.postMessage("getBridgeState");
334
+ }
335
+ });
336
+ this.postMessage("getBridgeState");
337
+ const proxy = new Proxy(initialState, {
338
+ get: (target, methodName) => {
339
+ if (methodName in target) {
340
+ return target[methodName];
341
+ }
342
+ this.postMessage("fallback", {
343
+ method: methodName
344
+ });
345
+ if (this.willMethodThrowOnError(methodName)) {
346
+ return (...args) => {
347
+ onFallback == null ? void 0 : onFallback(methodName, args);
348
+ return Promise.reject(new MethodNotFoundError(methodName));
349
+ };
350
+ } else {
351
+ console.warn(
352
+ `[WebViewBridge] ${methodName} is not defined, using fallback.`
227
353
  );
228
- },
229
- onFallback: () => {
230
- onFallback?.(methodName, args);
231
- },
232
- failHandler: throwOnError && new NativeMethodError(methodName)
233
- }),
234
- timeoutMs > 0 && timeout(timeoutMs, throwOnError)
235
- ].filter(Boolean)
236
- );
354
+ }
355
+ return () => Promise.resolve();
356
+ }
357
+ });
358
+ for (const [eventName, ...args] of (_a = window.nativeBatchedEvents) != null ? _a : []) {
359
+ this.emitter.emit(eventName, ...args);
360
+ }
361
+ window.nativeBatchedEvents = [];
362
+ onReady == null ? void 0 : onReady(proxy);
363
+ this.$proxy = proxy;
364
+ return proxy;
365
+ }
366
+ get proxy() {
367
+ return this.$proxy;
368
+ }
237
369
  };
370
+
371
+ // src/linkBridge.ts
238
372
  var linkBridge = (options = {
239
373
  timeout: 2e3,
240
374
  throwOnError: false
241
375
  }) => {
376
+ var _a;
242
377
  if (typeof window === "undefined") {
243
378
  return {
244
379
  store: {
@@ -247,94 +382,23 @@ var linkBridge = (options = {
247
382
  }
248
383
  };
249
384
  }
250
- const {
251
- timeout: timeoutMs = 2e3,
252
- throwOnError = false,
253
- onFallback,
254
- onReady
255
- } = options;
256
385
  if (!window.ReactNativeWebView) {
257
386
  console.warn("[WebViewBridge] Not in a WebView environment");
258
387
  }
259
- const bridgeMethods = window.__bridgeMethods__ ?? [];
388
+ const emitter = createEvents();
260
389
  if (!window.nativeEmitter) {
261
390
  window.nativeEmitter = emitter;
262
391
  }
263
- const willMethodThrowOnError = (methodName) => {
264
- return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
265
- };
266
- const target = bridgeMethods.reduce(
267
- (acc, methodName) => {
268
- return {
269
- ...acc,
270
- [methodName]: createNativeMethod({
271
- methodName,
272
- timeoutMs,
273
- throwOnError: willMethodThrowOnError(methodName),
274
- onFallback
275
- })
276
- };
277
- },
278
- {}
279
- );
280
- const loose = new Proxy(target, {
281
- get: (target2, methodName) => {
282
- if (methodName in target2 && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
283
- methodName
284
- )) {
285
- return target2[methodName];
286
- }
287
- return createNativeMethod({
288
- methodName,
289
- timeoutMs,
290
- throwOnError: willMethodThrowOnError(methodName),
291
- onFallback
292
- });
293
- }
294
- });
295
- Object.assign(target, {
296
- loose,
297
- store: linkBridgeStore(target),
298
- isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
299
- isNativeMethodAvailable(methodName) {
300
- return typeof methodName === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(methodName);
301
- },
302
- addEventListener: (eventName, listener) => {
303
- return emitter.on(`postMessage/${String(eventName)}`, listener);
304
- }
305
- });
306
- const proxy = new Proxy(target, {
307
- get: (target2, methodName) => {
308
- if (methodName in target2) {
309
- return target2[methodName];
310
- }
311
- window.ReactNativeWebView?.postMessage(
312
- JSON.stringify({
313
- type: "fallback",
314
- body: {
315
- method: methodName
316
- }
317
- })
318
- );
319
- if (willMethodThrowOnError(methodName)) {
320
- return (...args) => {
321
- onFallback?.(methodName, args);
322
- Promise.reject(new MethodNotFoundError(methodName));
323
- };
324
- } else {
325
- console.warn(
326
- `[WebViewBridge] ${methodName} is not defined, using fallback.`
327
- );
328
- }
329
- return () => Promise.resolve();
330
- }
331
- });
332
- for (const [eventName, ...args] of window.nativeBatchedEvents ?? []) {
333
- emitter.emit(eventName, ...args);
392
+ const bridgeMethods = (_a = window.__bridgeMethods__) != null ? _a : [];
393
+ const instance = new BridgeInstance(emitter, bridgeMethods, options);
394
+ if (bridgeMethods.length === 0) {
395
+ const unsubscribe = emitter.on("hydrate", ({ bridgeMethods: bridgeMethods2 }) => {
396
+ instance.hydrate(bridgeMethods2);
397
+ unsubscribe();
398
+ });
334
399
  }
335
- window.nativeBatchedEvents = [];
336
- onReady?.(proxy);
337
- return proxy;
400
+ instance.hydrate(bridgeMethods);
401
+ return instance.proxy;
338
402
  };
339
403
 
340
404
  // src/linkNativeMethod.ts
@@ -353,31 +417,33 @@ var registerWebMethod = (bridge) => {
353
417
  }
354
418
  const bridgeEntries = Object.entries(bridge);
355
419
  const bridgeNames = Object.keys(bridge);
356
- const emitter2 = createEvents();
357
- window.webEmitter = emitter2;
420
+ const emitter = createEvents();
421
+ window.webEmitter = emitter;
358
422
  for (const [funcName, func] of bridgeEntries) {
359
- const $func = async (eventId, args) => {
423
+ const $func = (eventId, args) => __async(void 0, null, function* () {
424
+ var _a, _b;
360
425
  try {
361
- const value = await func(...args);
362
- window.ReactNativeWebView?.postMessage(
426
+ const value = yield func(...args);
427
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
363
428
  JSON.stringify({
364
429
  type: "webMethodResponse",
365
430
  body: { funcName, eventId, value }
366
431
  })
367
432
  );
368
433
  } catch (e) {
369
- window.ReactNativeWebView?.postMessage(
434
+ (_b = window.ReactNativeWebView) == null ? void 0 : _b.postMessage(
370
435
  JSON.stringify({
371
436
  type: "webMethodError",
372
437
  body: { funcName, eventId, error: JSON.stringify(e) }
373
438
  })
374
439
  );
375
440
  }
376
- };
377
- emitter2.on(funcName, $func);
441
+ });
442
+ emitter.on(funcName, $func);
378
443
  }
379
444
  const register = () => {
380
- window.ReactNativeWebView?.postMessage(
445
+ var _a;
446
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
381
447
  JSON.stringify({
382
448
  type: "registerWebMethod",
383
449
  body: { bridgeNames }
@@ -390,8 +456,9 @@ var registerWebMethod = (bridge) => {
390
456
  return bridge;
391
457
  }
392
458
  document.addEventListener("visibilitychange", () => {
459
+ var _a;
393
460
  if (document.visibilityState === "visible") {
394
- window.ReactNativeWebView?.postMessage(
461
+ (_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage(
395
462
  JSON.stringify({
396
463
  type: "registerWebMethod",
397
464
  body: { bridgeNames }
@@ -0,0 +1,18 @@
1
+ import type { Bridge, BridgeStore, ExcludePrimitive, ExtractStore, ParserSchema } from "../../../../shared/util/src/types";
2
+ import { DefaultEmitter } from "../../../../shared/util/src";
3
+ import { LinkBridgeOptions } from "../linkBridge";
4
+ import { LinkBridge } from "../types";
5
+ export declare class BridgeInstance<T extends BridgeStore<T extends Bridge ? T : any>, V extends ParserSchema<any> = ParserSchema<any>> {
6
+ emitter: DefaultEmitter;
7
+ bridgeMethods: string[];
8
+ private options;
9
+ private defaultTimeoutMs;
10
+ private $proxy;
11
+ constructor(emitter: DefaultEmitter, bridgeMethods: string[], options: LinkBridgeOptions<T, V>);
12
+ private postMessage;
13
+ private createNativeMethod;
14
+ private willMethodThrowOnError;
15
+ private createLoose;
16
+ hydrate(bridgeMethods: string[], nativeInitialState?: Partial<T>): LinkBridge<ExtractStore<T>, Omit<T, "setState">, V>;
17
+ get proxy(): LinkBridge<ExcludePrimitive<ExtractStore<T>>, Omit<T, "setState">, V>;
18
+ }
@@ -1,6 +1,7 @@
1
1
  import { Bridge, BridgeStore, OnlyJSON } from "../../../../shared/util/src/types";
2
+ import { DefaultEmitter } from "../../../../shared/util/src";
2
3
  export type Store<BridgeObject extends Bridge> = ({ get, set, }: {
3
4
  get: () => BridgeObject;
4
5
  set: (newState: Partial<OnlyJSON<BridgeObject>>) => void;
5
6
  }) => BridgeObject;
6
- export declare const linkBridgeStore: <T extends BridgeStore<T extends Bridge ? T : any>>(initialState?: Partial<T>) => Omit<T, "setState">;
7
+ export declare const linkBridgeStore: <T extends BridgeStore<T extends Bridge ? T : any>>(emitter: DefaultEmitter, initialState?: Partial<T>, nativeInitialState?: Partial<T>) => Omit<T, "setState">;
@@ -11,9 +11,10 @@ export interface EventEmitter<Events extends EventsMap = DefaultEvents> {
11
11
  }>;
12
12
  on<K extends keyof Events>(this: this, event: K, cb: Events[K]): () => void;
13
13
  }
14
+ export type DefaultEmitter = EventEmitter<DefaultEvents>;
14
15
  export declare const createEvents: <Events extends EventsMap = DefaultEvents>() => EventEmitter<Events>;
15
16
  export interface CreateResolverOptions {
16
- emitter: EventEmitter<DefaultEvents>;
17
+ emitter: DefaultEmitter;
17
18
  evaluate: () => void;
18
19
  eventId: string;
19
20
  failHandler?: Error | false;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@webview-bridge/web",
3
3
  "type": "module",
4
- "version": "1.5.0",
4
+ "version": "1.5.1-rc.1",
5
5
  "description": "Fully Type-Safe Integration for React Native WebView and Web",
6
6
  "publishConfig": {
7
7
  "access": "public"