davbyte-mobile-bridge 0.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.
Files changed (40) hide show
  1. package/dist/core/defineHandler.d.ts +3 -0
  2. package/dist/core/defineHandler.d.ts.map +1 -0
  3. package/dist/core/defineHandler.js +3 -0
  4. package/dist/core/index.d.ts +5 -0
  5. package/dist/core/index.d.ts.map +1 -0
  6. package/dist/core/index.js +2 -0
  7. package/dist/core/registry.d.ts +13 -0
  8. package/dist/core/registry.d.ts.map +1 -0
  9. package/dist/core/registry.js +55 -0
  10. package/dist/core/types.d.ts +19 -0
  11. package/dist/core/types.d.ts.map +1 -0
  12. package/dist/core/types.js +1 -0
  13. package/dist/index.d.ts +10 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +5 -0
  16. package/dist/native/createNativeBridge.d.ts +20 -0
  17. package/dist/native/createNativeBridge.d.ts.map +1 -0
  18. package/dist/native/createNativeBridge.js +37 -0
  19. package/dist/native/index.d.ts +5 -0
  20. package/dist/native/index.d.ts.map +1 -0
  21. package/dist/native/index.js +2 -0
  22. package/dist/native/plugins/tabNavigation.d.ts +9 -0
  23. package/dist/native/plugins/tabNavigation.d.ts.map +1 -0
  24. package/dist/native/plugins/tabNavigation.js +18 -0
  25. package/dist/web/createWebBridge.d.ts +18 -0
  26. package/dist/web/createWebBridge.d.ts.map +1 -0
  27. package/dist/web/createWebBridge.js +49 -0
  28. package/dist/web/index.d.ts +8 -0
  29. package/dist/web/index.d.ts.map +1 -0
  30. package/dist/web/index.js +12 -0
  31. package/dist/web/plugins/tabSync.d.ts +11 -0
  32. package/dist/web/plugins/tabSync.d.ts.map +1 -0
  33. package/dist/web/plugins/tabSync.js +23 -0
  34. package/dist/web/postToNative.d.ts +3 -0
  35. package/dist/web/postToNative.d.ts.map +1 -0
  36. package/dist/web/postToNative.js +9 -0
  37. package/dist/web/useBridgeHandlers.d.ts +6 -0
  38. package/dist/web/useBridgeHandlers.d.ts.map +1 -0
  39. package/dist/web/useBridgeHandlers.js +14 -0
  40. package/package.json +57 -0
@@ -0,0 +1,3 @@
1
+ import type { BridgeHandler } from "./types.js";
2
+ export declare function defineHandler<TPayload = unknown>(type: string, handle: BridgeHandler<TPayload>["handle"]): BridgeHandler<TPayload>;
3
+ //# sourceMappingURL=defineHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defineHandler.d.ts","sourceRoot":"","sources":["../../src/core/defineHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,aAAa,CAAC,QAAQ,GAAG,OAAO,EAC9C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,GACxC,aAAa,CAAC,QAAQ,CAAC,CAEzB"}
@@ -0,0 +1,3 @@
1
+ export function defineHandler(type, handle) {
2
+ return { type, handle };
3
+ }
@@ -0,0 +1,5 @@
1
+ export type { BridgeMessage, BridgeHandler, BridgeHandlerContext, BridgePlugin } from "./types.js";
2
+ export { defineHandler } from "./defineHandler.js";
3
+ export { createHandlerRegistry } from "./registry.js";
4
+ export type { HandlerRegistry, HandlerRegistryOptions } from "./registry.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { defineHandler } from "./defineHandler.js";
2
+ export { createHandlerRegistry } from "./registry.js";
@@ -0,0 +1,13 @@
1
+ import type { BridgeHandler, BridgeHandlerContext, BridgeMessage, BridgePlugin } from "./types.js";
2
+ export type HandlerRegistryOptions = {
3
+ onUnknown?: (type: string, payload: unknown) => void;
4
+ onError?: (error: unknown, message: BridgeMessage) => void;
5
+ };
6
+ export type HandlerRegistry = ReturnType<typeof createHandlerRegistry>;
7
+ export declare function createHandlerRegistry(options?: HandlerRegistryOptions): {
8
+ on: (handler: BridgeHandler) => () => void;
9
+ use: (pluginOrHandler: BridgePlugin | BridgeHandler) => () => void;
10
+ dispatch: (message: BridgeMessage, ctx: BridgeHandlerContext) => Promise<void>;
11
+ destroy: () => void;
12
+ };
13
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnG,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEvE,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B;kBAInD,aAAa,KAAG,MAAM,IAAI;2BAYjB,YAAY,GAAG,aAAa,KAAG,MAAM,IAAI;wBAqB5D,aAAa,OACjB,oBAAoB,KACxB,OAAO,CAAC,IAAI,CAAC;mBAgBI,IAAI;EAQzB"}
@@ -0,0 +1,55 @@
1
+ export function createHandlerRegistry(options = {}) {
2
+ const handlersByType = new Map();
3
+ const cleanups = [];
4
+ function on(handler) {
5
+ let set = handlersByType.get(handler.type);
6
+ if (!set) {
7
+ set = new Set();
8
+ handlersByType.set(handler.type, set);
9
+ }
10
+ set.add(handler);
11
+ return () => {
12
+ set?.delete(handler);
13
+ };
14
+ }
15
+ function use(pluginOrHandler) {
16
+ if ("register" in pluginOrHandler) {
17
+ const cleanup = pluginOrHandler.register({
18
+ on,
19
+ send: () => {
20
+ throw new Error(`Bridge plugin "${pluginOrHandler.name}" cannot send during registration`);
21
+ },
22
+ });
23
+ cleanups.push(cleanup);
24
+ return () => {
25
+ cleanup();
26
+ const idx = cleanups.indexOf(cleanup);
27
+ if (idx >= 0)
28
+ cleanups.splice(idx, 1);
29
+ };
30
+ }
31
+ return on(pluginOrHandler);
32
+ }
33
+ async function dispatch(message, ctx) {
34
+ const handlers = handlersByType.get(message.type);
35
+ if (!handlers || handlers.size === 0) {
36
+ options.onUnknown?.(message.type, message.payload);
37
+ return;
38
+ }
39
+ for (const handler of handlers) {
40
+ try {
41
+ await handler.handle(message.payload, ctx);
42
+ }
43
+ catch (error) {
44
+ options.onError?.(error, message);
45
+ }
46
+ }
47
+ }
48
+ function destroy() {
49
+ for (const cleanup of cleanups.splice(0)) {
50
+ cleanup();
51
+ }
52
+ handlersByType.clear();
53
+ }
54
+ return { on, use, dispatch, destroy };
55
+ }
@@ -0,0 +1,19 @@
1
+ export type BridgeMessage = {
2
+ type: string;
3
+ payload?: unknown;
4
+ };
5
+ export type BridgeHandlerContext = {
6
+ send: (type: string, payload?: unknown) => void;
7
+ };
8
+ export type BridgeHandler<TPayload = unknown> = {
9
+ type: string;
10
+ handle: (payload: TPayload, ctx: BridgeHandlerContext) => void | Promise<void>;
11
+ };
12
+ export type BridgePlugin = {
13
+ name: string;
14
+ register: (registry: {
15
+ on: (handler: BridgeHandler) => () => void;
16
+ send: (type: string, payload?: unknown) => void;
17
+ }) => () => void;
18
+ };
19
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,QAAQ,GAAG,OAAO,IAAI;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,QAAQ,EAAE;QACnB,EAAE,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,MAAM,IAAI,CAAC;QAC3C,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;KACjD,KAAK,MAAM,IAAI,CAAC;CAClB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ export { defineHandler, createHandlerRegistry, type BridgeMessage, type BridgeHandler, type BridgeHandlerContext, type BridgePlugin, type HandlerRegistry, type HandlerRegistryOptions, } from "./core/index.js";
2
+ export { createWebBridge, postToNative, isNativeApp, useBridgeHandlers } from "./web/index.js";
3
+ export type { WebBridge, WebBridgeOptions } from "./web/index.js";
4
+ export { createNativeBridge } from "./native/index.js";
5
+ export type { NativeBridge, NativeBridgeOptions, PostToWebView } from "./native/index.js";
6
+ export { tabSyncPlugin, syncTabToNative, TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC, } from "./web/plugins/tabSync.js";
7
+ export type { TabSyncPluginOptions } from "./web/plugins/tabSync.js";
8
+ export { tabNavigationPlugin } from "./native/plugins/tabNavigation.js";
9
+ export type { TabNavigationPluginOptions } from "./native/plugins/tabNavigation.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE1F,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,YAAY,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { defineHandler, createHandlerRegistry, } from "./core/index.js";
2
+ export { createWebBridge, postToNative, isNativeApp, useBridgeHandlers } from "./web/index.js";
3
+ export { createNativeBridge } from "./native/index.js";
4
+ export { tabSyncPlugin, syncTabToNative, TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC, } from "./web/plugins/tabSync.js";
5
+ export { tabNavigationPlugin } from "./native/plugins/tabNavigation.js";
@@ -0,0 +1,20 @@
1
+ import type { BridgeMessage } from "../core/types.js";
2
+ import { TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC } from "../web/plugins/tabSync.js";
3
+ export type PostToWebView = (data: BridgeMessage) => void;
4
+ export type NativeBridgeOptions = {
5
+ postToWebView: PostToWebView;
6
+ onUnknown?: (type: string, payload: unknown) => void;
7
+ onError?: (error: unknown, message: BridgeMessage) => void;
8
+ };
9
+ export type NativeBridge = ReturnType<typeof createNativeBridge>;
10
+ export declare function createNativeBridge(options: NativeBridgeOptions): {
11
+ use: (pluginOrHandler: import("../core/types.js").BridgePlugin | import("../core/types.js").BridgeHandler) => () => void;
12
+ on: (handler: import("../core/types.js").BridgeHandler) => () => void;
13
+ send: (type: string, payload?: unknown) => void;
14
+ navigateTo: (view: string) => void;
15
+ handleIncoming: (message: BridgeMessage) => Promise<void>;
16
+ createMessageHandler: () => (data: BridgeMessage) => void;
17
+ destroy: () => void;
18
+ };
19
+ export { TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC };
20
+ //# sourceMappingURL=createNativeBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createNativeBridge.d.ts","sourceRoot":"","sources":["../../src/native/createNativeBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE7E,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEjE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB;;;iBAYzC,MAAM,YAAY,OAAO,KAAG,IAAI;uBAI1B,MAAM,KAAG,IAAI;8BAIA,aAAa,KAAG,OAAO,CAAC,IAAI,CAAC;gCAInC,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;;EAe/D;AAED,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { createHandlerRegistry } from "../core/registry.js";
2
+ import { TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC } from "../web/plugins/tabSync.js";
3
+ export function createNativeBridge(options) {
4
+ const registry = createHandlerRegistry({
5
+ onUnknown: options.onUnknown,
6
+ onError: options.onError,
7
+ });
8
+ const ctx = {
9
+ send: (type, payload) => {
10
+ options.postToWebView({ type, payload });
11
+ },
12
+ };
13
+ function send(type, payload) {
14
+ options.postToWebView({ type, payload });
15
+ }
16
+ function navigateTo(view) {
17
+ send(TAB_SYNC_NAVIGATE, view);
18
+ }
19
+ async function handleIncoming(message) {
20
+ await registry.dispatch(message, ctx);
21
+ }
22
+ function createMessageHandler() {
23
+ return (data) => {
24
+ void handleIncoming(data);
25
+ };
26
+ }
27
+ return {
28
+ use: registry.use.bind(registry),
29
+ on: registry.on.bind(registry),
30
+ send,
31
+ navigateTo,
32
+ handleIncoming,
33
+ createMessageHandler,
34
+ destroy: registry.destroy.bind(registry),
35
+ };
36
+ }
37
+ export { TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC };
@@ -0,0 +1,5 @@
1
+ export { createNativeBridge } from "./createNativeBridge.js";
2
+ export type { NativeBridge, NativeBridgeOptions, PostToWebView } from "./createNativeBridge.js";
3
+ export { tabNavigationPlugin } from "./plugins/tabNavigation.js";
4
+ export type { TabNavigationPluginOptions } from "./plugins/tabNavigation.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,YAAY,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createNativeBridge } from "./createNativeBridge.js";
2
+ export { tabNavigationPlugin } from "./plugins/tabNavigation.js";
@@ -0,0 +1,9 @@
1
+ import type { BridgePlugin } from "../../core/types.js";
2
+ export type TabNavigationPluginOptions<TView extends string = string> = {
3
+ validViews: readonly TView[];
4
+ getActiveTab: () => TView;
5
+ setActiveTab: (view: TView) => void;
6
+ onTabSync?: (view: TView) => void;
7
+ };
8
+ export declare function tabNavigationPlugin<TView extends string>(options: TabNavigationPluginOptions<TView>): BridgePlugin;
9
+ //# sourceMappingURL=tabNavigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabNavigation.d.ts","sourceRoot":"","sources":["../../../src/native/plugins/tabNavigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,MAAM,0BAA0B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI;IACtE,UAAU,EAAE,SAAS,KAAK,EAAE,CAAC;IAC7B,YAAY,EAAE,MAAM,KAAK,CAAC;IAC1B,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,MAAM,EACtD,OAAO,EAAE,0BAA0B,CAAC,KAAK,CAAC,GACzC,YAAY,CAed"}
@@ -0,0 +1,18 @@
1
+ import { defineHandler } from "../../core/defineHandler.js";
2
+ import { TAB_SYNC_SYNC } from "../../web/plugins/tabSync.js";
3
+ export function tabNavigationPlugin(options) {
4
+ return {
5
+ name: "tab-navigation",
6
+ register({ on }) {
7
+ return on(defineHandler(TAB_SYNC_SYNC, (payload) => {
8
+ if (typeof payload !== "string")
9
+ return;
10
+ const view = payload;
11
+ if (!options.validViews.includes(view))
12
+ return;
13
+ options.setActiveTab(view);
14
+ options.onTabSync?.(view);
15
+ }));
16
+ },
17
+ };
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { BridgeMessage } from "../core/types.js";
2
+ import { isNativeApp, postToNative } from "./postToNative.js";
3
+ export type WebBridgeOptions = {
4
+ onUnknown?: (type: string, payload: unknown) => void;
5
+ onError?: (error: unknown, message: BridgeMessage) => void;
6
+ };
7
+ export type WebBridge = ReturnType<typeof createWebBridge>;
8
+ export declare function createWebBridge(options?: WebBridgeOptions): {
9
+ use: (pluginOrHandler: import("../core/types.js").BridgePlugin | import("../core/types.js").BridgeHandler) => () => void;
10
+ on: (handler: import("../core/types.js").BridgeHandler) => () => void;
11
+ send: (type: string, payload?: unknown) => void;
12
+ handleIncoming: (message: BridgeMessage) => Promise<void>;
13
+ createMessageListener: () => () => void;
14
+ isNativeApp: typeof isNativeApp;
15
+ destroy: () => void;
16
+ };
17
+ export { postToNative, isNativeApp };
18
+ //# sourceMappingURL=createWebBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createWebBridge.d.ts","sourceRoot":"","sources":["../../src/web/createWebBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAE3D,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB;;;iBAUxC,MAAM,YAAY,OAAO,KAAG,IAAI;8BAIb,aAAa,KAAG,OAAO,CAAC,IAAI,CAAC;iCAIlC,MAAM,IAAI;;;EAqC7C;AAED,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { createHandlerRegistry } from "../core/registry.js";
2
+ import { isNativeApp, postToNative } from "./postToNative.js";
3
+ export function createWebBridge(options = {}) {
4
+ const registry = createHandlerRegistry({
5
+ onUnknown: options.onUnknown,
6
+ onError: options.onError,
7
+ });
8
+ const ctx = {
9
+ send: (type, payload) => postToNative(type, payload),
10
+ };
11
+ function send(type, payload) {
12
+ postToNative(type, payload);
13
+ }
14
+ async function handleIncoming(message) {
15
+ await registry.dispatch(message, ctx);
16
+ }
17
+ function createMessageListener() {
18
+ const handleMessage = (event) => {
19
+ try {
20
+ const rawData = event instanceof MessageEvent ? event.data : event.detail;
21
+ if (!rawData)
22
+ return;
23
+ const data = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
24
+ if (!data || typeof data !== "object" || !("type" in data))
25
+ return;
26
+ void handleIncoming(data);
27
+ }
28
+ catch {
29
+ // Invalid JSON or structure — ignore
30
+ }
31
+ };
32
+ window.addEventListener("message", handleMessage);
33
+ document.addEventListener("message", handleMessage);
34
+ return () => {
35
+ window.removeEventListener("message", handleMessage);
36
+ document.removeEventListener("message", handleMessage);
37
+ };
38
+ }
39
+ return {
40
+ use: registry.use.bind(registry),
41
+ on: registry.on.bind(registry),
42
+ send,
43
+ handleIncoming,
44
+ createMessageListener,
45
+ isNativeApp,
46
+ destroy: registry.destroy.bind(registry),
47
+ };
48
+ }
49
+ export { postToNative, isNativeApp };
@@ -0,0 +1,8 @@
1
+ export declare function postToNative(type: string, payload?: unknown): void;
2
+ export declare function isNativeApp(): boolean;
3
+ export { createWebBridge } from "./createWebBridge.js";
4
+ export { useBridgeHandlers } from "./useBridgeHandlers.js";
5
+ export type { WebBridge, WebBridgeOptions } from "./createWebBridge.js";
6
+ export { tabSyncPlugin, syncTabToNative, TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC, } from "./plugins/tabSync.js";
7
+ export type { TabSyncPluginOptions } from "./plugins/tabSync.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAOlE;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export function postToNative(type, payload) {
2
+ if (typeof window !== "undefined" && "ReactNativeWebView" in window) {
3
+ const webView = window.ReactNativeWebView;
4
+ webView?.postMessage(JSON.stringify({ type, payload }));
5
+ }
6
+ }
7
+ export function isNativeApp() {
8
+ return typeof window !== "undefined" && "ReactNativeWebView" in window;
9
+ }
10
+ export { createWebBridge } from "./createWebBridge.js";
11
+ export { useBridgeHandlers } from "./useBridgeHandlers.js";
12
+ export { tabSyncPlugin, syncTabToNative, TAB_SYNC_NAVIGATE, TAB_SYNC_SYNC, } from "./plugins/tabSync.js";
@@ -0,0 +1,11 @@
1
+ import type { BridgePlugin } from "../../core/types.js";
2
+ export declare const TAB_SYNC_NAVIGATE = "navigateTo";
3
+ export declare const TAB_SYNC_SYNC = "syncTab";
4
+ export type TabSyncPluginOptions<TView extends string = string> = {
5
+ setView: (view: TView) => void;
6
+ onViewChange?: (view: TView) => void;
7
+ };
8
+ /** Send current view to native (call when web view changes). */
9
+ export declare function syncTabToNative<TView extends string>(view: TView): void;
10
+ export declare function tabSyncPlugin<TView extends string>(options: TabSyncPluginOptions<TView>): BridgePlugin;
11
+ //# sourceMappingURL=tabSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabSync.d.ts","sourceRoot":"","sources":["../../../src/web/plugins/tabSync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAC9C,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,MAAM,MAAM,oBAAoB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI;IAChE,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;CACtC,CAAC;AAEF,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI,CAIvE;AAED,wBAAgB,aAAa,CAAC,KAAK,SAAS,MAAM,EAChD,OAAO,EAAE,oBAAoB,CAAC,KAAK,CAAC,GACnC,YAAY,CAcd"}
@@ -0,0 +1,23 @@
1
+ import { defineHandler } from "../../core/defineHandler.js";
2
+ import { isNativeApp, postToNative } from "../postToNative.js";
3
+ export const TAB_SYNC_NAVIGATE = "navigateTo";
4
+ export const TAB_SYNC_SYNC = "syncTab";
5
+ /** Send current view to native (call when web view changes). */
6
+ export function syncTabToNative(view) {
7
+ if (isNativeApp()) {
8
+ postToNative(TAB_SYNC_SYNC, view);
9
+ }
10
+ }
11
+ export function tabSyncPlugin(options) {
12
+ return {
13
+ name: "tab-sync",
14
+ register({ on }) {
15
+ return on(defineHandler(TAB_SYNC_NAVIGATE, (payload) => {
16
+ if (typeof payload === "string") {
17
+ options.setView(payload);
18
+ options.onViewChange?.(payload);
19
+ }
20
+ }));
21
+ },
22
+ };
23
+ }
@@ -0,0 +1,3 @@
1
+ export declare function postToNative(type: string, payload?: unknown): void;
2
+ export declare function isNativeApp(): boolean;
3
+ //# sourceMappingURL=postToNative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postToNative.d.ts","sourceRoot":"","sources":["../../src/web/postToNative.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAOlE;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC"}
@@ -0,0 +1,9 @@
1
+ export function postToNative(type, payload) {
2
+ if (typeof window !== "undefined" && "ReactNativeWebView" in window) {
3
+ const webView = window.ReactNativeWebView;
4
+ webView?.postMessage(JSON.stringify({ type, payload }));
5
+ }
6
+ }
7
+ export function isNativeApp() {
8
+ return typeof window !== "undefined" && "ReactNativeWebView" in window;
9
+ }
@@ -0,0 +1,6 @@
1
+ import type { BridgeHandler, BridgePlugin } from "../core/types.js";
2
+ import type { WebBridge } from "./createWebBridge.js";
3
+ type HandlerInput = BridgeHandler | BridgePlugin;
4
+ export declare function useBridgeHandlers(bridge: WebBridge, handlers: HandlerInput[]): void;
5
+ export {};
6
+ //# sourceMappingURL=useBridgeHandlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBridgeHandlers.d.ts","sourceRoot":"","sources":["../../src/web/useBridgeHandlers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,KAAK,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAEjD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,YAAY,EAAE,GACvB,IAAI,CAaN"}
@@ -0,0 +1,14 @@
1
+ import { useEffect, useRef } from "react";
2
+ export function useBridgeHandlers(bridge, handlers) {
3
+ const handlersRef = useRef(handlers);
4
+ handlersRef.current = handlers;
5
+ useEffect(() => {
6
+ const cleanups = handlersRef.current.map((h) => bridge.use(h));
7
+ const removeListener = bridge.createMessageListener();
8
+ return () => {
9
+ removeListener();
10
+ for (const cleanup of cleanups)
11
+ cleanup();
12
+ };
13
+ }, [bridge]);
14
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "davbyte-mobile-bridge",
3
+ "version": "0.1.0",
4
+ "description": "Extensible bridge for DavByte hybrid Expo + WebView apps",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./core": {
14
+ "types": "./dist/core/index.d.ts",
15
+ "import": "./dist/core/index.js"
16
+ },
17
+ "./web": {
18
+ "types": "./dist/web/index.d.ts",
19
+ "import": "./dist/web/index.js"
20
+ },
21
+ "./native": {
22
+ "types": "./dist/native/index.d.ts",
23
+ "import": "./dist/native/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsc",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest"
33
+ },
34
+ "peerDependencies": {
35
+ "react": ">=18.0.0"
36
+ },
37
+ "peerDependenciesMeta": {
38
+ "react": {
39
+ "optional": true
40
+ }
41
+ },
42
+ "devDependencies": {
43
+ "@types/react": "^19.1.0",
44
+ "react": "^19.1.0",
45
+ "typescript": "^5.7.0",
46
+ "vitest": "^4.0.18"
47
+ },
48
+ "license": "MIT",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/DavByte/create-app.git",
52
+ "directory": "packages/davbyte-mobile-bridge"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public"
56
+ }
57
+ }