@webview-bridge/web 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  MethodNotFoundError: () => MethodNotFoundError,
24
+ NativeMethodError: () => NativeMethodError,
24
25
  linkNativeMethod: () => linkNativeMethod,
25
26
  registerWebMethod: () => registerWebMethod
26
27
  });
@@ -33,6 +34,12 @@ var MethodNotFoundError = class extends Error {
33
34
  this.name = "MethodNotFoundError";
34
35
  }
35
36
  };
37
+ var NativeMethodError = class extends Error {
38
+ constructor(methodName) {
39
+ super(`An error occurred in the native bridge: ${methodName}`);
40
+ this.name = "NativeMethodError";
41
+ }
42
+ };
36
43
 
37
44
  // ../../shared/util/src/createEvents.ts
38
45
  var createEvents = () => ({
@@ -50,12 +57,23 @@ var createEvents = () => ({
50
57
  };
51
58
  }
52
59
  });
53
- var createResolver = (emitter2, method, eventId, evaluate) => {
54
- return new Promise((resolve) => {
55
- const unbind = emitter2.on(`${method}-${eventId}`, (data) => {
56
- unbind();
57
- resolve(data);
58
- });
60
+ var createResolver = (emitter2, method, eventId, evaluate, failHandler = false) => {
61
+ return new Promise((resolve, reject) => {
62
+ const unbind = emitter2.on(
63
+ `${method}-${eventId}`,
64
+ (data, throwOccurred) => {
65
+ unbind();
66
+ if (throwOccurred) {
67
+ if (failHandler instanceof Error) {
68
+ reject(failHandler);
69
+ } else {
70
+ resolve(void 0);
71
+ }
72
+ } else {
73
+ resolve(data);
74
+ }
75
+ }
76
+ );
59
77
  evaluate();
60
78
  });
61
79
  };
@@ -72,16 +90,44 @@ var createRandomId = (size = ID_LENGTH) => {
72
90
  };
73
91
 
74
92
  // ../../shared/util/src/timeout.ts
75
- var timeout = (ms) => {
76
- return new Promise((_, reject) => {
93
+ var timeout = (ms, throwOnError = true) => {
94
+ return new Promise((resolve, reject) => {
77
95
  setTimeout(() => {
78
- reject(new Error("Timeout"));
96
+ if (throwOnError) {
97
+ reject(new Error("Timeout"));
98
+ } else {
99
+ resolve(void 0);
100
+ }
79
101
  }, ms);
80
102
  });
81
103
  };
82
104
 
83
105
  // src/linkNativeMethod.ts
84
106
  var emitter = createEvents();
107
+ var createNativeMethod = (method, timeoutMs, throwOnError) => (...args) => {
108
+ const eventId = createRandomId();
109
+ return Promise.race([
110
+ createResolver(
111
+ emitter,
112
+ method,
113
+ eventId,
114
+ () => {
115
+ window.ReactNativeWebView?.postMessage(
116
+ JSON.stringify({
117
+ type: "bridge",
118
+ body: {
119
+ method,
120
+ eventId,
121
+ args
122
+ }
123
+ })
124
+ );
125
+ },
126
+ throwOnError && new NativeMethodError(method)
127
+ ),
128
+ timeout(timeoutMs, throwOnError)
129
+ ]);
130
+ };
85
131
  var linkNativeMethod = (options = {
86
132
  timeout: 2e3,
87
133
  throwOnError: false
@@ -98,35 +144,42 @@ var linkNativeMethod = (options = {
98
144
  if (!window.nativeEmitter) {
99
145
  window.nativeEmitter = emitter;
100
146
  }
147
+ const willMethodThrowOnError = (methodName) => {
148
+ return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
149
+ };
101
150
  const target = bridgeMethods.reduce(
102
151
  (acc, method) => {
103
152
  return {
104
153
  ...acc,
105
- [method]: (...args) => {
106
- const eventId = createRandomId();
107
- return Promise.race([
108
- createResolver(emitter, method, eventId, () => {
109
- window.ReactNativeWebView?.postMessage(
110
- JSON.stringify({
111
- type: "bridge",
112
- body: {
113
- method,
114
- eventId,
115
- args
116
- }
117
- })
118
- );
119
- }),
120
- timeout(timeoutMs)
121
- ]);
122
- }
154
+ [method]: createNativeMethod(
155
+ method,
156
+ timeoutMs,
157
+ willMethodThrowOnError(method)
158
+ )
123
159
  };
124
160
  },
125
161
  {
126
162
  isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
127
- isNativeMethodAvailable: (method) => typeof method === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(method)
163
+ isNativeMethodAvailable(method) {
164
+ return typeof method === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(method);
165
+ }
128
166
  }
129
167
  );
168
+ const loose = new Proxy(target, {
169
+ get: (target2, method) => {
170
+ if (method in target2 && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
171
+ method
172
+ )) {
173
+ return target2[method];
174
+ }
175
+ return createNativeMethod(
176
+ method,
177
+ timeoutMs,
178
+ willMethodThrowOnError(method)
179
+ );
180
+ }
181
+ });
182
+ Object.assign(target, { loose });
130
183
  return new Proxy(target, {
131
184
  get: (target2, method) => {
132
185
  if (method in target2) {
@@ -141,9 +194,7 @@ var linkNativeMethod = (options = {
141
194
  })
142
195
  );
143
196
  onFallback?.(method);
144
- if (throwOnError === true) {
145
- return () => Promise.reject(new MethodNotFoundError(method));
146
- } else if (Array.isArray(throwOnError) && throwOnError.includes(method)) {
197
+ if (willMethodThrowOnError(method)) {
147
198
  return () => Promise.reject(new MethodNotFoundError(method));
148
199
  } else {
149
200
  console.warn(
@@ -196,6 +247,7 @@ var registerWebMethod = (bridge) => {
196
247
  // Annotate the CommonJS export names for ESM import in node:
197
248
  0 && (module.exports = {
198
249
  MethodNotFoundError,
250
+ NativeMethodError,
199
251
  linkNativeMethod,
200
252
  registerWebMethod
201
253
  });
@@ -5,6 +5,12 @@ var MethodNotFoundError = class extends Error {
5
5
  this.name = "MethodNotFoundError";
6
6
  }
7
7
  };
8
+ var NativeMethodError = class extends Error {
9
+ constructor(methodName) {
10
+ super(`An error occurred in the native bridge: ${methodName}`);
11
+ this.name = "NativeMethodError";
12
+ }
13
+ };
8
14
 
9
15
  // ../../shared/util/src/createEvents.ts
10
16
  var createEvents = () => ({
@@ -22,12 +28,23 @@ var createEvents = () => ({
22
28
  };
23
29
  }
24
30
  });
25
- var createResolver = (emitter2, method, eventId, evaluate) => {
26
- return new Promise((resolve) => {
27
- const unbind = emitter2.on(`${method}-${eventId}`, (data) => {
28
- unbind();
29
- resolve(data);
30
- });
31
+ var createResolver = (emitter2, method, eventId, evaluate, failHandler = false) => {
32
+ return new Promise((resolve, reject) => {
33
+ const unbind = emitter2.on(
34
+ `${method}-${eventId}`,
35
+ (data, throwOccurred) => {
36
+ unbind();
37
+ if (throwOccurred) {
38
+ if (failHandler instanceof Error) {
39
+ reject(failHandler);
40
+ } else {
41
+ resolve(void 0);
42
+ }
43
+ } else {
44
+ resolve(data);
45
+ }
46
+ }
47
+ );
31
48
  evaluate();
32
49
  });
33
50
  };
@@ -44,16 +61,44 @@ var createRandomId = (size = ID_LENGTH) => {
44
61
  };
45
62
 
46
63
  // ../../shared/util/src/timeout.ts
47
- var timeout = (ms) => {
48
- return new Promise((_, reject) => {
64
+ var timeout = (ms, throwOnError = true) => {
65
+ return new Promise((resolve, reject) => {
49
66
  setTimeout(() => {
50
- reject(new Error("Timeout"));
67
+ if (throwOnError) {
68
+ reject(new Error("Timeout"));
69
+ } else {
70
+ resolve(void 0);
71
+ }
51
72
  }, ms);
52
73
  });
53
74
  };
54
75
 
55
76
  // src/linkNativeMethod.ts
56
77
  var emitter = createEvents();
78
+ var createNativeMethod = (method, timeoutMs, throwOnError) => (...args) => {
79
+ const eventId = createRandomId();
80
+ return Promise.race([
81
+ createResolver(
82
+ emitter,
83
+ method,
84
+ eventId,
85
+ () => {
86
+ window.ReactNativeWebView?.postMessage(
87
+ JSON.stringify({
88
+ type: "bridge",
89
+ body: {
90
+ method,
91
+ eventId,
92
+ args
93
+ }
94
+ })
95
+ );
96
+ },
97
+ throwOnError && new NativeMethodError(method)
98
+ ),
99
+ timeout(timeoutMs, throwOnError)
100
+ ]);
101
+ };
57
102
  var linkNativeMethod = (options = {
58
103
  timeout: 2e3,
59
104
  throwOnError: false
@@ -70,35 +115,42 @@ var linkNativeMethod = (options = {
70
115
  if (!window.nativeEmitter) {
71
116
  window.nativeEmitter = emitter;
72
117
  }
118
+ const willMethodThrowOnError = (methodName) => {
119
+ return throwOnError === true || Array.isArray(throwOnError) && throwOnError.includes(methodName);
120
+ };
73
121
  const target = bridgeMethods.reduce(
74
122
  (acc, method) => {
75
123
  return {
76
124
  ...acc,
77
- [method]: (...args) => {
78
- const eventId = createRandomId();
79
- return Promise.race([
80
- createResolver(emitter, method, eventId, () => {
81
- window.ReactNativeWebView?.postMessage(
82
- JSON.stringify({
83
- type: "bridge",
84
- body: {
85
- method,
86
- eventId,
87
- args
88
- }
89
- })
90
- );
91
- }),
92
- timeout(timeoutMs)
93
- ]);
94
- }
125
+ [method]: createNativeMethod(
126
+ method,
127
+ timeoutMs,
128
+ willMethodThrowOnError(method)
129
+ )
95
130
  };
96
131
  },
97
132
  {
98
133
  isWebViewBridgeAvailable: Boolean(window.ReactNativeWebView) && bridgeMethods.length > 0,
99
- isNativeMethodAvailable: (method) => typeof method === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(method)
134
+ isNativeMethodAvailable(method) {
135
+ return typeof method === "string" && Boolean(window.ReactNativeWebView) && bridgeMethods.includes(method);
136
+ }
100
137
  }
101
138
  );
139
+ const loose = new Proxy(target, {
140
+ get: (target2, method) => {
141
+ if (method in target2 && !["isWebViewBridgeAvailable", "isNativeMethodAvailable"].includes(
142
+ method
143
+ )) {
144
+ return target2[method];
145
+ }
146
+ return createNativeMethod(
147
+ method,
148
+ timeoutMs,
149
+ willMethodThrowOnError(method)
150
+ );
151
+ }
152
+ });
153
+ Object.assign(target, { loose });
102
154
  return new Proxy(target, {
103
155
  get: (target2, method) => {
104
156
  if (method in target2) {
@@ -113,9 +165,7 @@ var linkNativeMethod = (options = {
113
165
  })
114
166
  );
115
167
  onFallback?.(method);
116
- if (throwOnError === true) {
117
- return () => Promise.reject(new MethodNotFoundError(method));
118
- } else if (Array.isArray(throwOnError) && throwOnError.includes(method)) {
168
+ if (willMethodThrowOnError(method)) {
119
169
  return () => Promise.reject(new MethodNotFoundError(method));
120
170
  } else {
121
171
  console.warn(
@@ -167,6 +217,7 @@ var registerWebMethod = (bridge) => {
167
217
  };
168
218
  export {
169
219
  MethodNotFoundError,
220
+ NativeMethodError,
170
221
  linkNativeMethod,
171
222
  registerWebMethod
172
223
  };
@@ -1,3 +1,6 @@
1
1
  export declare class MethodNotFoundError extends Error {
2
2
  constructor(methodName: string);
3
3
  }
4
+ export declare class NativeMethodError extends Error {
5
+ constructor(methodName: string);
6
+ }
@@ -1,7 +1,7 @@
1
- import { Bridge, WithAvailable } from "./types";
1
+ import { Bridge, NativeMethod } from "./types";
2
2
  export interface LinkNativeMethodOptions<BridgeObject extends Bridge> {
3
3
  timeout?: number;
4
- throwOnError?: boolean | (keyof BridgeObject)[];
5
- onFallback?: (method: keyof BridgeObject) => void;
4
+ throwOnError?: boolean | (keyof BridgeObject)[] | string[];
5
+ onFallback?: (method: string) => void;
6
6
  }
7
- export declare const linkNativeMethod: <BridgeObject extends Bridge>(options?: LinkNativeMethodOptions<BridgeObject>) => WithAvailable<BridgeObject>;
7
+ export declare const linkNativeMethod: <BridgeObject extends Bridge>(options?: LinkNativeMethodOptions<BridgeObject>) => NativeMethod<BridgeObject>;
@@ -1,6 +1,12 @@
1
1
  export type AsyncFunction = (...args: any[]) => Promise<any>;
2
2
  export type Bridge = Record<string, AsyncFunction>;
3
- export type WithAvailable<T> = {
3
+ export type NativeMethod<T> = {
4
4
  isWebViewBridgeAvailable: boolean;
5
- isNativeMethodAvailable: (method: keyof T) => boolean;
5
+ isNativeMethodAvailable(method: keyof T): boolean;
6
+ isNativeMethodAvailable(method: string): boolean;
7
+ loose: {
8
+ [K in keyof T]: (...args: any[]) => any;
9
+ } & {
10
+ [key: string]: (...args: any[]) => any;
11
+ };
6
12
  } & T;
@@ -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>, method: string, eventId: string, evaluate: () => void) => Promise<unknown>;
15
+ export declare const createResolver: (emitter: EventEmitter<DefaultEvents>, method: string, eventId: string, evaluate: () => void, failHandler?: Error | false) => Promise<unknown>;
16
16
  export {};
@@ -1 +1 @@
1
- export declare const timeout: (ms: number) => Promise<unknown>;
1
+ export declare const timeout: (ms: number, throwOnError?: boolean) => Promise<unknown>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@webview-bridge/web",
3
3
  "type": "module",
4
- "version": "1.0.5",
4
+ "version": "1.1.0",
5
5
  "description": "Fully Type-Safe Integration for React Native WebView and Web",
6
6
  "publishConfig": {
7
7
  "access": "public"