diff --git a/README.md b/README.md
index 34a784f..58dd990 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,11 @@ If you are familiar with `socket.io`, you already know how to use this package.
`msgio` is based on postMessage.
+Occasionally, we need to build web apps with iframes agross different domains. Communication between these iframes always make us uncomfortable
+.Using this library less pain you will suffer.
+
+## Examples
+All examples are in the 'examples' directory in this repository.
## Install
diff --git a/examples/create-react-app/.editorconfig b/examples/create-react-app/.editorconfig
new file mode 100644
index 0000000..fdda3f6
--- /dev/null
+++ b/examples/create-react-app/.editorconfig
@@ -0,0 +1,17 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# General settings for whole project
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_size = 2
diff --git a/examples/create-react-app/README.md b/examples/create-react-app/README.md
new file mode 100644
index 0000000..2cee08d
--- /dev/null
+++ b/examples/create-react-app/README.md
@@ -0,0 +1,5 @@
+# create-react-app
+1. Open two terminal window.
+2. Run `PORT=3456 npm start` in the first terminal.
+3. Run `PORT=4567 npm start` in the second terminal.
+4. Open `http://localhost:3456/host` in the browser and see the console.
diff --git a/examples/create-react-app/package.json b/examples/create-react-app/package.json
new file mode 100644
index 0000000..6433554
--- /dev/null
+++ b/examples/create-react-app/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "create-react-app",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.16.5",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/user-event": "^13.5.0",
+ "@types/jest": "^27.5.2",
+ "@types/node": "^16.18.18",
+ "@types/react": "^18.0.28",
+ "@types/react-dom": "^18.0.11",
+ "msgio": "^1.0.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.9.0",
+ "react-scripts": "5.0.1",
+ "typescript": "^4.9.5",
+ "web-vitals": "^2.1.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/examples/create-react-app/public/favicon.ico b/examples/create-react-app/public/favicon.ico
new file mode 100644
index 0000000..a11777c
Binary files /dev/null and b/examples/create-react-app/public/favicon.ico differ
diff --git a/examples/create-react-app/public/index.html b/examples/create-react-app/public/index.html
new file mode 100644
index 0000000..aa069f2
--- /dev/null
+++ b/examples/create-react-app/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/examples/create-react-app/src/App.tsx b/examples/create-react-app/src/App.tsx
new file mode 100644
index 0000000..4996491
--- /dev/null
+++ b/examples/create-react-app/src/App.tsx
@@ -0,0 +1,51 @@
+import {useCallback, SyntheticEvent} from 'react';
+import {Iframe} from 'msgio';
+
+const summarize = (...args: any) => args.reduce((acc: any, cur: any) => (acc + cur), 0);
+
+const multiply = (a: any, b: any) => Promise.resolve(a * b);
+
+const throw1 = () => {
+ throw new Error('Host throws Error. Error1');
+};
+
+const throw2 = () => {
+ return Promise.reject(new Error('Host throws Error: Error2'));
+};
+
+const App = () => {
+ const handleLoad = useCallback(
+ (e: SyntheticEvent) => {
+ const host = new Iframe(e.target as HTMLIFrameElement);
+
+ host.on('connect', socket => {
+ console.log('host:connected');
+
+ socket.on('guest_event_1', (...args: any) => {
+ console.log('host:main:guest_event_1', ...args);
+ });
+
+ socket.emit('host_event_1', {name: 'host_event_1', a: 'a', x: 1});
+
+ socket.func('summarize', summarize);
+
+ socket.func('multiply', multiply);
+
+ socket.func('throw1', throw1);
+
+ socket.func('throw2', throw2);
+
+ socket.call('concat', 'hello', ' ', 'world', '!').then((result: any) => {
+ console.log('host:return:', result);
+ });
+ });
+ },
+ [],
+ );
+
+ return (
+
+ );
+};
+
+export default App;
diff --git a/examples/create-react-app/src/Guest.tsx b/examples/create-react-app/src/Guest.tsx
new file mode 100644
index 0000000..6f977c7
--- /dev/null
+++ b/examples/create-react-app/src/Guest.tsx
@@ -0,0 +1,56 @@
+import {Guest as IframeGuest} from 'msgio';
+
+const guest = new IframeGuest({host: '//localhost:3456'});
+
+const concat = (...args: any) => (args.join(''));
+
+guest.on('connect', socket => {
+ console.log('guest:connected');
+
+ guest.resize({width: 400, height: 600});
+
+ socket.on('host_event_1', (...args: any) => {
+ console.log('guest:main:host_event_1', ...args);
+ });
+
+ socket.emit('guest_event_1', {name: 'guest_event_1', b: 'b', y: 2});
+
+ socket.func('concat', concat);
+
+ socket.call('summarize', 1, 2).then((result: any) => {
+ console.log('guest:return:', result);
+ });
+
+ socket.call('summarize', 3, 4).then((result: any) => {
+ console.log('guest:return:', result);
+ });
+
+ socket.call('multiply', 5, 6).then((result: any) => {
+ console.log('guest:return:', result);
+ });
+
+ socket.call('throw1').catch((e: Error) => {
+ console.log('guest:return:', e);
+ });
+
+ socket.call('throw2')
+ .then((data: any) => {
+ console.log(data);
+ return data;
+ })
+ .catch((e: Error) => {
+ console.log('guest:return:', e);
+ });
+
+ socket.call('foo').catch((e: Error) => {
+ console.log('guest:return:', e);
+ });
+})
+
+const Guest = () => {
+ return (
+ This is the Guest.
+ );
+};
+
+export default Guest;
diff --git a/examples/create-react-app/src/Host.tsx b/examples/create-react-app/src/Host.tsx
new file mode 100644
index 0000000..5311954
--- /dev/null
+++ b/examples/create-react-app/src/Host.tsx
@@ -0,0 +1,54 @@
+import {useCallback, SyntheticEvent} from 'react';
+import {Iframe} from 'msgio';
+
+const summarize = (...args: number[]) => args.reduce((acc: any, cur: any) => (acc + cur), 0);
+
+const multiply = (a: number, b: number) => Promise.resolve(a * b);
+
+const throw1 = () => {
+ throw new Error('Host throws Error. Error1');
+};
+
+const throw2 = () => {
+ return Promise.reject(new Error('Host throws Error: Error2'));
+};
+
+const Host = () => {
+ const handleLoad = useCallback(
+ (e: SyntheticEvent) => {
+ const host = new Iframe(e.target as HTMLIFrameElement);
+
+ host.on('connect', socket => {
+ console.log('host:connected');
+
+ socket.on('guest_event_1', (...args: any) => {
+ console.log('host:main:guest_event_1', ...args);
+ });
+
+ socket.emit('host_event_1', {name: 'host_event_1', a: 'a', x: 1});
+
+ socket.func('summarize', summarize);
+
+ socket.func('multiply', multiply);
+
+ socket.func('throw1', throw1);
+
+ socket.func('throw2', throw2);
+
+ socket.call('concat', 'hello', ' ', 'world', '!').then((result: any) => {
+ console.log('host:return:', result);
+ });
+ });
+ },
+ [],
+ );
+
+ return (
+ <>
+ This is the Host.
+
+ >
+ );
+};
+
+export default Host;
diff --git a/examples/create-react-app/src/index.tsx b/examples/create-react-app/src/index.tsx
new file mode 100644
index 0000000..cccf5df
--- /dev/null
+++ b/examples/create-react-app/src/index.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import {createBrowserRouter, RouterProvider} from "react-router-dom";
+import Host from './Host';
+import Guest from './Guest';
+import reportWebVitals from './reportWebVitals';
+
+
+const root = ReactDOM.createRoot(
+ document.getElementById('root') as HTMLElement
+);
+
+const router = createBrowserRouter([
+ {
+ path: "/host",
+ element: ,
+ },
+ {
+ path: "/guest",
+ element: ,
+ },
+]);
+
+root.render(
+
+
+
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+reportWebVitals();
diff --git a/examples/create-react-app/src/reportWebVitals.ts b/examples/create-react-app/src/reportWebVitals.ts
new file mode 100644
index 0000000..e28f08a
--- /dev/null
+++ b/examples/create-react-app/src/reportWebVitals.ts
@@ -0,0 +1,15 @@
+import {ReportHandler} from 'web-vitals';
+
+const reportWebVitals = (onPerfEntry?: ReportHandler) => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import('web-vitals').then(({getCLS, getFID, getFCP, getLCP, getTTFB}) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
+};
+
+export default reportWebVitals;
diff --git a/examples/create-react-app/tsconfig.json b/examples/create-react-app/tsconfig.json
new file mode 100644
index 0000000..a273b0c
--- /dev/null
+++ b/examples/create-react-app/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": [
+ "src"
+ ]
+}
diff --git a/examples/umd/README.md b/examples/umd/README.md
new file mode 100644
index 0000000..0255651
--- /dev/null
+++ b/examples/umd/README.md
@@ -0,0 +1,5 @@
+# umd
+1. Open two terminal window.
+2. Run `npx serve -l 3456` in the first terminal.
+3. Run `npx serve -l 4567` in the second terminal.
+4. Open `http://localhost:3456/host.html` in the browser and see the console.
diff --git a/examples/umd/guest.html b/examples/umd/guest.html
new file mode 100644
index 0000000..0959990
--- /dev/null
+++ b/examples/umd/guest.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+ msgio:guest
+
+
+ This is the iframe guest
+
+
+
+
diff --git a/examples/umd/host.html b/examples/umd/host.html
new file mode 100644
index 0000000..e99f89c
--- /dev/null
+++ b/examples/umd/host.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+ msgio:host
+
+
+ See output int the console!
+ This is the iframe host
+
+
+
+
+
+
+
diff --git a/examples/umd/msgio.min.js b/examples/umd/msgio.min.js
new file mode 100644
index 0000000..214be95
--- /dev/null
+++ b/examples/umd/msgio.min.js
@@ -0,0 +1,2 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).msgio={})}(this,(function(e){"use strict";function t(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n({events:{},emit(e,...t){let n=this.events[e]||[];for(let e=0,r=n.length;e{this.events[e]=this.events[e]?.filter((e=>t!==e))}}});var v="application/msgio+json",h=r((function e(n){var r=this;t(this,e),o(this,"emitter",p()),o(this,"origin",window.location.origin),o(this,"socketId","none"),o(this,"sendPacket",(function(e,t){r.receiver.target.postMessage({mime:v,type:e,socket:"CONNECT"===e?r.socketId:void 0,body:t},r.receiver.origin)})),o(this,"isValidEvent",(function(e){var t=e.origin,n=e.data,o=n.mime,i=n.type,a=n.socket;return t===r.receiver.origin&&(o===v&&("CONNECT"===i||a===r.socketId))})),o(this,"on",(function(e,t){r.emitter.on(e,t)})),this.receiver=n}));var m=function(e){var t=document.createElement("a");t.href=e;var n=t.protocol.length>4?t.protocol:window.location.protocol,r=t.host.length>0?"80"===t.port||"443"===t.port?t.hostname:t.host:window.location.host;return t.origin||"".concat(n,"//").concat(r)},y=function(){return"".concat(((e=21)=>crypto.getRandomValues(new Uint8Array(e)).reduce(((e,t)=>e+((t&=63)<36?t.toString(36):t<62?(t-26).toString(36).toUpperCase():t>62?"-":"_")),""))(),"")},g=function(e){return e.data.type},E=function(e){return e.data.body},w=r((function e(n){var r=this;t(this,e),o(this,"emitter",p()),o(this,"isValidEvent",(function(e){var t=e.origin,n=e.data,o=n.mime,i=n.socket;return t===r.connection.receiver.origin&&(o===v&&i===r.id)})),o(this,"sendPacket",(function(e,t){var n=r.connection.receiver,o=n.target,i=n.origin;o.postMessage({mime:v,type:e,socket:r.id,body:t},i)})),o(this,"onEvent",(function(e){if(r.isValidEvent(e)&&"SOCKET_EVENT"===g(e)){var t=E(e),n=t.event,o=t.payload;r.emitter.emit(n,o)}})),o(this,"on",(function(e,t){r.emitter.on(e,t)})),o(this,"emit",(function(e,t){r.sendPacket("SOCKET_EVENT",{event:e,payload:t})})),o(this,"func",(function(e,t){if("function"!=typeof t)throw new Error("The object supplied to 'function' must be a function!");r.functionRegistry.set(e,t)})),o(this,"onCallRequest",(function(e){if(r.isValidEvent(e)&&"SOCKET_CALL_REQUEST"===g(e)){var t=E(e),n=t.callId,o=t.fname,i=t.args,a=function(e){r.sendPacket("SOCKET_CALL_RESPONSE",{callId:n,fname:o,payload:e})},s=function(e){return a({error:!0,result:(t=e,{name:t.name,message:t.message})});var t};if(r.functionRegistry.has(o))try{var c=r.functionRegistry.get(o).apply(void 0,f(i));Promise.resolve(c).then((function(e){return a({error:!1,result:e})})).catch(s)}catch(e){s(e)}else s(new ReferenceError("".concat(o," is not defined!")))}})),o(this,"onCallResponse",(function(e){if(r.isValidEvent(e)&&"SOCKET_CALL_RESPONSE"===g(e)){var t=E(e),n=t.callId,o=t.payload,i=o.error,a=o.result;if(r.callRegistry.has(n)){var s,c,u,f,l=r.callRegistry.get(n),d=l.resolve,p=l.reject;i?p((c=(s=a).name,u=s.message,f={Error:Error,EvalError:EvalError,RangeError:RangeError,ReferenceError:ReferenceError,SyntaxError:SyntaxError,TypeError:TypeError,URIError:URIError},c in f?new f[c](u):new Error("Unknown Error type!"))):d(a),r.callRegistry.delete(n)}}})),o(this,"call",(function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o");return o(c(r=n.call(this,{target:e.contentWindow,origin:m(e.src)})),"desiredSocketId",y()),o(c(r),"onConnect",(function(e){r.isValidEvent(e)&&("CONNECT"===g(e)&&e.data.body===r.desiredSocketId&&(r.socketId=r.desiredSocketId,r.desiredSocketId="verified",r.emitter.emit("connect",new w(c(r))),window.removeEventListener("message",r.onConnect)))})),o(c(r),"onResize",(function(e){if(r.isValidEvent(e)&&"RESIZE"===g(e)){var t=e.data.body,n=t.width,o=t.height;r.dom.width=n,r.dom.height=o}})),r.dom=e,window.addEventListener("message",r.onConnect),window.addEventListener("message",r.onResize),r.sendPacket("CONNECT",r.desiredSocketId),r}return r(a)}(h),R=function(e){i(a,e);var n=u(a);function a(e){var r;t(this,a);var i=e.host;return o(c(r=n.call(this,{target:window.parent,origin:m(i)})),"onConnect",(function(e){if(r.isValidEvent(e)&&"CONNECT"===g(e)){var t=E(e);t&&(r.socketId=t,r.sendPacket("CONNECT",r.socketId),r.emitter.emit("connect",new w(c(r))),window.removeEventListener("message",r.onConnect))}})),o(c(r),"resize",(function(e){r.sendPacket("RESIZE",e)})),r.option=e,window.addEventListener("message",r.onConnect),r}return r(a)}(h);e.Guest=R,e.Iframe=b}));
+//# sourceMappingURL=msgio.min.js.map
diff --git a/examples/umd/msgio.min.js.map b/examples/umd/msgio.min.js.map
new file mode 100644
index 0000000..ddab909
--- /dev/null
+++ b/examples/umd/msgio.min.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"msgio.min.js","sources":["../node_modules/nanoevents/index.js","../src/constants.ts","../src/endpoint.ts","../src/utils.ts","../node_modules/nanoid/index.browser.js","../src/socket.ts","../src/iframe.ts","../src/guest.ts"],"sourcesContent":["export let createNanoEvents = () => ({\n events: {},\n emit(event, ...args) {\n let callbacks = this.events[event] || []\n for (let i = 0, length = callbacks.length; i < length; i++) {\n callbacks[i](...args)\n }\n },\n on(event, cb) {\n this.events[event]?.push(cb) || (this.events[event] = [cb])\n return () => {\n this.events[event] = this.events[event]?.filter(i => cb !== i)\n }\n }\n})\n","/* eslint import/prefer-default-export: 0 */\nexport const MIME_TYPE = 'application/msgio+json';\n","import {createNanoEvents} from 'nanoevents';\nimport {EndpointEvent, EndpointEventType, Receiver} from './types';\nimport type Socket from './socket';\nimport {MIME_TYPE} from './constants';\n\nclass Endpoint {\n emitter = createNanoEvents();\n\n origin = window.location.origin;\n\n socketId = 'none';\n\n receiver: Receiver;\n\n constructor(receiver: Receiver) {\n this.receiver = receiver;\n }\n\n sendPacket = (type: EndpointEventType, body: any) => {\n this.receiver.target.postMessage({\n mime: MIME_TYPE,\n type,\n socket: type === 'CONNECT' ? this.socketId : undefined,\n body,\n }, this.receiver.origin);\n };\n\n isValidEvent = (e: EndpointEvent) => {\n const {origin, data: {mime, type, socket}} = e;\n\n if (origin !== this.receiver.origin) {\n return false;\n }\n\n if (mime !== MIME_TYPE) {\n return false;\n }\n\n if (type !== 'CONNECT' && socket !== this.socketId) {\n return false;\n }\n\n return true;\n };\n\n on = (event: 'connect', fn: (socket: Socket) => void) => {\n this.emitter.on(event, fn);\n };\n}\n\nexport default Endpoint;\n","import {nanoid} from 'nanoid';\nimport {SocketError, ErrorNameConstructorMap} from './types';\n\nexport const resolveOrigin = (url: string) => {\n const a = document.createElement('a');\n\n a.href = url;\n\n const protocol = a.protocol.length > 4 ? a.protocol : window.location.protocol;\n\n const host = (() => {\n if (a.host.length > 0) {\n return (a.port === '80' || a.port === '443') ? a.hostname : a.host;\n }\n return window.location.host;\n })();\n\n return a.origin || `${protocol}//${host}`;\n};\n\nexport const generateId = () => `${nanoid()}`;\n\nexport const typeOf = (e: MessageEvent) => e.data.type;\n\nexport const bodyOf = (e: MessageEvent) => e.data.body;\n\nexport const encodeError = ({name, message}: Error) => ({name, message});\n\nexport const decodeError = ({name, message}: SocketError) => {\n const ErrorConstructor: ErrorNameConstructorMap = {\n Error,\n EvalError,\n RangeError,\n ReferenceError,\n SyntaxError,\n TypeError,\n URIError,\n };\n\n if (name in ErrorConstructor) {\n return new ErrorConstructor[name](message);\n }\n\n return new Error('Unknown Error type!');\n};\n","export { urlAlphabet } from './url-alphabet/index.js'\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1\n let step = -~((1.6 * mask * defaultSize) / alphabet.length)\n return (size = defaultSize) => {\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let j = step\n while (j--) {\n id += alphabet[bytes[j] & mask] || ''\n if (id.length === size) return id\n }\n }\n }\n}\nexport let customAlphabet = (alphabet, size = 21) =>\n customRandom(alphabet, size, random)\nexport let nanoid = (size = 21) =>\n crypto.getRandomValues(new Uint8Array(size)).reduce((id, byte) => {\n byte &= 63\n if (byte < 36) {\n id += byte.toString(36)\n } else if (byte < 62) {\n id += (byte - 26).toString(36).toUpperCase()\n } else if (byte > 62) {\n id += '-'\n } else {\n id += '_'\n }\n return id\n }, '')\n","import {createNanoEvents} from 'nanoevents';\nimport {SocketEvent, SocketEventType, SocketCallResponseEventPayload, SocketCallRegistryValue} from './types';\nimport type Endpoint from './endpoint';\nimport {MIME_TYPE} from './constants';\nimport {generateId, typeOf, bodyOf, encodeError, decodeError} from './utils';\n\nclass Socket {\n emitter = createNanoEvents();\n\n id: string;\n\n connection: Endpoint;\n\n functionRegistry: Map any>;\n\n callRegistry: Map;\n\n constructor(connection: Endpoint) {\n this.connection = connection;\n\n this.id = this.connection.socketId;\n\n this.functionRegistry = new Map();\n\n this.callRegistry = new Map();\n\n window.addEventListener('message', this.onEvent);\n window.addEventListener('message', this.onCallRequest);\n window.addEventListener('message', this.onCallResponse);\n }\n\n isValidEvent = (e: SocketEvent) => {\n const {origin, data: {mime, socket}} = e;\n\n if (origin !== this.connection.receiver.origin) {\n return false;\n }\n\n if (mime !== MIME_TYPE) {\n return false;\n }\n\n if (socket !== this.id) {\n return false;\n }\n\n return true;\n };\n\n sendPacket = (type: SocketEventType, body: any) => {\n const {target, origin} = this.connection.receiver;\n\n target.postMessage({\n mime: MIME_TYPE,\n type,\n socket: this.id,\n body,\n }, origin);\n };\n\n onEvent = (e: SocketEvent) => {\n if (!this.isValidEvent(e)) {\n return;\n }\n\n if (typeOf(e) !== 'SOCKET_EVENT') {\n return;\n }\n\n const {event, payload} = bodyOf(e);\n\n this.emitter.emit(event, payload);\n };\n\n on = (event: string, fn: (...args: any) => void) => {\n this.emitter.on(event, fn);\n };\n\n emit = (event: string, payload: any) => {\n this.sendPacket('SOCKET_EVENT', {event, payload});\n };\n\n func = (fname: string, fn: (...args: any) => void) => {\n if (typeof fn !== 'function') {\n throw new Error('The object supplied to \\'function\\' must be a function!');\n }\n\n this.functionRegistry.set(fname, fn);\n };\n\n onCallRequest = (e: SocketEvent) => {\n if (!this.isValidEvent(e)) {\n return;\n }\n\n if (typeOf(e) !== 'SOCKET_CALL_REQUEST') {\n return;\n }\n\n const {callId, fname, args} = bodyOf(e);\n\n const send = (payload: SocketCallResponseEventPayload) => {\n this.sendPacket('SOCKET_CALL_RESPONSE', {callId, fname, payload});\n };\n\n const sendError = (result: Error) => send({error: true, result: encodeError(result)});\n\n const sendResult = (result: unknown) => send({error: false, result});\n\n if (!this.functionRegistry.has(fname)) {\n sendError(new ReferenceError(`${fname} is not defined!`));\n return;\n }\n\n try {\n // NOTE: need typescirpt's non-null assertion operator ! below\n // see Line 186 above and https://github.com/microsoft/TypeScript/issues/41045\n const result = this.functionRegistry.get(fname)!(...args);\n\n Promise.resolve(result)\n .then(sendResult)\n .catch(sendError);\n } catch (error) {\n sendError(error as Error);\n }\n };\n\n onCallResponse = (e: SocketEvent) => {\n if (!this.isValidEvent(e)) {\n return;\n }\n\n if (typeOf(e) !== 'SOCKET_CALL_RESPONSE') {\n return;\n }\n\n const {callId, payload: {error, result}} = bodyOf(e);\n\n if (!this.callRegistry.has(callId)) {\n return;\n }\n\n // NOTE: need typescirpt's non-null assertion operator ! below\n // see Line 186 above and https://github.com/microsoft/TypeScript/issues/41045\n const {resolve, reject} = this.callRegistry.get(callId)!;\n\n if (error) {\n reject(decodeError(result));\n } else {\n resolve(result);\n }\n\n this.callRegistry.delete(callId);\n };\n\n call = (fname: string, ...args: any[]) => {\n const callId = generateId();\n\n this.sendPacket('SOCKET_CALL_REQUEST', {callId, fname, args});\n\n return new Promise((resolve, reject) => {\n this.callRegistry.set(callId, {callId, fname, args, resolve, reject});\n });\n };\n}\n\nexport default Socket;\n","import {EndpointEvent} from './types';\nimport Endpoint from './endpoint';\nimport Socket from './socket';\nimport {resolveOrigin, generateId, typeOf} from './utils';\n\nclass Iframe extends Endpoint {\n dom: HTMLIFrameElement;\n\n desiredSocketId = generateId();\n\n constructor(dom: HTMLIFrameElement) {\n if (dom.tagName !== 'IFRAME' || !dom.contentWindow) {\n throw new Error('The DOM Node supplied is not a valid iframe node!');\n }\n\n super({\n target: dom.contentWindow,\n origin: resolveOrigin(dom.src),\n });\n\n this.dom = dom;\n\n window.addEventListener('message', this.onConnect);\n window.addEventListener('message', this.onResize);\n\n this.sendPacket('CONNECT', this.desiredSocketId);\n }\n\n onConnect = (e: EndpointEvent) => {\n if (!this.isValidEvent(e)) {\n return;\n }\n\n if (typeOf(e) !== 'CONNECT') {\n return;\n }\n\n const repliedSocketId = e.data.body;\n\n if (repliedSocketId !== this.desiredSocketId) {\n return;\n }\n\n this.socketId = this.desiredSocketId;\n\n this.desiredSocketId = 'verified';\n\n this.emitter.emit('connect', new Socket(this));\n\n window.removeEventListener('message', this.onConnect);\n };\n\n onResize = (e: EndpointEvent) => {\n if (!this.isValidEvent(e)) {\n return;\n }\n\n if (typeOf(e) !== 'RESIZE') {\n return;\n }\n\n const {width, height} = e.data.body;\n\n this.dom.width = width;\n this.dom.height = height;\n };\n}\n\nexport default Iframe;\n","import {GuestOption, EndpointEvent, FrameSize} from './types';\nimport Endpoint from './endpoint';\nimport Socket from './socket';\nimport {resolveOrigin, typeOf, bodyOf} from './utils';\n\nclass Guest extends Endpoint {\n option: GuestOption; // only for debug\n\n constructor(option: GuestOption) {\n const {host} = option;\n\n super({\n target: window.parent,\n origin: resolveOrigin(host),\n });\n\n this.option = option;\n\n window.addEventListener('message', this.onConnect);\n }\n\n onConnect = (e: EndpointEvent) => {\n if (!this.isValidEvent(e)) {\n return;\n }\n\n if (typeOf(e) !== 'CONNECT') {\n return;\n }\n\n const desiredSocketId = bodyOf(e);\n\n if (!desiredSocketId) {\n return;\n }\n\n this.socketId = desiredSocketId;\n\n this.sendPacket('CONNECT', this.socketId);\n\n this.emitter.emit('connect', new Socket(this));\n\n window.removeEventListener('message', this.onConnect);\n };\n\n resize = (size: FrameSize) => {\n this.sendPacket('RESIZE', size);\n };\n}\n\nexport default Guest;\n"],"names":["createNanoEvents","events","emit","event","args","callbacks","this","i","length","on","cb","push","filter","MIME_TYPE","Endpoint","_createClass","receiver","_this","_classCallCheck","_defineProperty","window","location","origin","type","body","target","postMessage","mime","socket","socketId","undefined","e","_e$data","data","fn","emitter","resolveOrigin","url","a","document","createElement","href","protocol","host","port","hostname","concat","generateId","size","crypto","getRandomValues","Uint8Array","reduce","id","byte","toString","toUpperCase","nanoid","typeOf","bodyOf","Socket","connection","_this$connection$rece","isValidEvent","_bodyOf","payload","sendPacket","fname","Error","functionRegistry","set","_bodyOf2","callId","send","sendError","result","error","_ref","name","message","has","get","apply","_toConsumableArray","Promise","resolve","then","catch","ReferenceError","_bodyOf3","_bodyOf3$payload","callRegistry","_ref2","ErrorConstructor","reject","EvalError","RangeError","SyntaxError","TypeError","URIError","delete","_len","arguments","Array","_key","Map","addEventListener","onEvent","onCallRequest","onCallResponse","Iframe","_Endpoint","_inherits","_super","_createSuper","dom","tagName","contentWindow","_assertThisInitialized","call","src","desiredSocketId","removeEventListener","onConnect","_e$data$body","width","height","onResize","Guest","option","parent"],"mappings":"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","x_google_ignoreList":[0,4]}
\ No newline at end of file
diff --git a/examples/webpack/.browserslistrc b/examples/webpack/.browserslistrc
new file mode 100644
index 0000000..0223254
--- /dev/null
+++ b/examples/webpack/.browserslistrc
@@ -0,0 +1,3 @@
+>0.2%
+not dead
+not op_mini all
diff --git a/examples/webpack/.editorconfig b/examples/webpack/.editorconfig
new file mode 100644
index 0000000..4432917
--- /dev/null
+++ b/examples/webpack/.editorconfig
@@ -0,0 +1,17 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# General settings for whole project
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_size = 2
\ No newline at end of file
diff --git a/examples/webpack/.eslintrc.js b/examples/webpack/.eslintrc.js
new file mode 100644
index 0000000..d5481b1
--- /dev/null
+++ b/examples/webpack/.eslintrc.js
@@ -0,0 +1,14 @@
+module.exports = {
+ extends: [
+ 'airbnb-base',
+ 'airbnb-typescript/base',
+ ],
+ parserOptions: {
+ project: './tsconfig.json',
+ },
+ rules: {
+ 'object-curly-newline': ['error', {'multiline': true }],
+ '@typescript-eslint/indent': ['error', 4],
+ '@typescript-eslint/object-curly-spacing': ['error', 'never'],
+ },
+};
diff --git a/examples/webpack/.npmrc b/examples/webpack/.npmrc
new file mode 100644
index 0000000..7549542
--- /dev/null
+++ b/examples/webpack/.npmrc
@@ -0,0 +1 @@
+registry=https://registry.npmmirror.com
diff --git a/examples/webpack/README.md b/examples/webpack/README.md
new file mode 100644
index 0000000..5a3628b
--- /dev/null
+++ b/examples/webpack/README.md
@@ -0,0 +1,5 @@
+# webpack
+1. Open two terminal window.
+2. Run `npx webpack-dev-server --port 3456` in the first terminal.
+3. Run `npx webpack-dev-server --port 4567` in the second terminal.
+4. Open `http://localhost:3456/host.html` in the browser and see the console.
diff --git a/examples/webpack/package.json b/examples/webpack/package.json
new file mode 100644
index 0000000..dd0e477
--- /dev/null
+++ b/examples/webpack/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "msgio-example-webpack",
+ "version": "1.0.1",
+ "description": "",
+ "dependencies": {
+ "msgio": "^1.0.1",
+ "nanoevents": "^7.0.1",
+ "nanoid": "^4.0.1"
+ },
+ "devDependencies": {
+ "@babel/cli": "^7.21.0",
+ "@babel/core": "^7.21.3",
+ "@babel/preset-env": "^7.20.2",
+ "@babel/preset-typescript": "^7.21.0",
+ "@tsconfig/recommended": "^1.0.2",
+ "@typescript-eslint/eslint-plugin": "^5.55.0",
+ "@typescript-eslint/parser": "^5.55.0",
+ "eslint": "^8.36.0",
+ "eslint-config-airbnb-base": "^15.0.0",
+ "eslint-config-airbnb-typescript": "^17.0.0",
+ "eslint-plugin-import": "^2.27.5",
+ "html-loader": "^4.2.0",
+ "html-webpack-plugin": "^5.5.0",
+ "ts-loader": "^9.4.2",
+ "typescript": "^5.0.2",
+ "webpack": "^5.76.2",
+ "webpack-cli": "^5.0.1",
+ "webpack-dev-server": "^4.12.0"
+ },
+ "author": "Zhixing Han ",
+ "license": "MIT"
+}
diff --git a/examples/webpack/public/favicon.ico b/examples/webpack/public/favicon.ico
new file mode 100644
index 0000000..e69de29
diff --git a/examples/webpack/public/guest.html b/examples/webpack/public/guest.html
new file mode 100644
index 0000000..b8bb6fe
--- /dev/null
+++ b/examples/webpack/public/guest.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ msgio:guest
+
+
+ msgio:guest
+
+
diff --git a/examples/webpack/public/host.html b/examples/webpack/public/host.html
new file mode 100644
index 0000000..ae8781f
--- /dev/null
+++ b/examples/webpack/public/host.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ msgio:host
+
+
+ msgio:host
+
+
+
+
+
diff --git a/examples/webpack/src/guest.ts b/examples/webpack/src/guest.ts
new file mode 100644
index 0000000..cfddb7e
--- /dev/null
+++ b/examples/webpack/src/guest.ts
@@ -0,0 +1,48 @@
+import {Guest} from 'msgio';
+
+const guest = new Guest({host: '//localhost:3456'});
+
+const concat = (...args: any) => (args.join(''));
+
+guest.on('connect', socket => {
+ console.log('guest:connected');
+
+ guest.resize({width: 400, height: 600});
+
+ socket.on('host_event_1', (...args: any) => {
+ console.log('guest:main:host_event_1', ...args);
+ });
+
+ socket.emit('guest_event_1', {name: 'guest_event_1', b: 'b', y: 2});
+
+ socket.func('concat', concat);
+
+ socket.call('summarize', 1, 2).then((result: any) => {
+ console.log('guest:return:', result);
+ });
+
+ socket.call('summarize', 3, 4).then((result: any) => {
+ console.log('guest:return:', result);
+ });
+
+ socket.call('multiply', 5, 6).then((result: any) => {
+ console.log('guest:return:', result);
+ });
+
+ socket.call('throw1').catch((e: Error) => {
+ console.log('guest:return:', e);
+ });
+
+ socket.call('throw2')
+ .then((data: any) => {
+ console.log(data);
+ return data;
+ })
+ .catch((e: Error) => {
+ console.log('guest:return:', e);
+ });
+
+ socket.call('foo').catch((e: Error) => {
+ console.log('guest:return:', e);
+ });
+})
diff --git a/examples/webpack/src/host.ts b/examples/webpack/src/host.ts
new file mode 100644
index 0000000..2a0055e
--- /dev/null
+++ b/examples/webpack/src/host.ts
@@ -0,0 +1,45 @@
+import {Iframe} from 'msgio';
+
+const iframe = document.getElementById('iframe');
+
+let sum = 0;
+
+const summarize = (...args: any) => args.reduce((acc: any, cur: any) => (acc + cur), 0);
+
+const multiply = (a: any, b: any) => Promise.resolve(a * b);
+
+const throw1 = () => {
+ throw new Error('Host throws Error. Error1');
+};
+
+const throw2 = () => {
+ return Promise.reject(new Error('Host throws Error: Error2'));
+};
+
+const onLoad = (e: Event) => {
+ const host = new Iframe(e.target as HTMLIFrameElement);
+
+ host.on('connect', socket => {
+ console.log('host:connected');
+
+ socket.on('guest_event_1', (...args: any) => {
+ console.log('host:main:guest_event_1', ...args);
+ });
+
+ socket.emit('host_event_1', {name: 'host_event_1', a: 'a', x: 1});
+
+ socket.func('summarize', summarize);
+
+ socket.func('multiply', multiply);
+
+ socket.func('throw1', throw1);
+
+ socket.func('throw2', throw2);
+
+ socket.call('concat', 'hello', ' ', 'world', '!').then((result: any) => {
+ console.log('host:return:', result);
+ });
+ });
+};
+
+iframe!.addEventListener('load', onLoad);
diff --git a/examples/webpack/tsconfig.json b/examples/webpack/tsconfig.json
new file mode 100644
index 0000000..282a7be
--- /dev/null
+++ b/examples/webpack/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "@tsconfig/recommended/tsconfig.json",
+ "include": ["src/**/*"],
+ "compilerOptions": {
+ "outDir": "./dist/",
+ "noImplicitAny": true,
+ "module": "es6",
+ "target": "es5",
+ "allowJs": true,
+ "moduleResolution": "node"
+ }
+}
diff --git a/examples/webpack/webpack.config.js b/examples/webpack/webpack.config.js
new file mode 100755
index 0000000..bf9b5bb
--- /dev/null
+++ b/examples/webpack/webpack.config.js
@@ -0,0 +1,40 @@
+const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+module.exports = {
+ mode: 'development',
+ entry: {
+ host: path.resolve(__dirname, 'src/host'),
+ guest: path.resolve(__dirname, 'src/guest'),
+ },
+ output: {
+ filename: 'assets/js/[name].bundle.js',
+ chunkFilename: 'assets/js/[name].chunk.js',
+ },
+ resolve: {
+ extensions: ['.js', '.ts'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.ts$/,
+ loader: 'ts-loader',
+ exclude: /node_modules/,
+ },
+ ],
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ template: path.resolve(__dirname, 'public/host.html'),
+ filename: 'host.html',
+ inject: 'body',
+ chunks: ['host'],
+ }),
+ new HtmlWebpackPlugin({
+ template: path.resolve(__dirname, 'public/guest.html'),
+ filename: 'guest.html',
+ inject: 'body',
+ chunks: ['guest'],
+ }),
+ ],
+};
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index abc18a7..0000000
--- a/jest.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- clearMocks: true,
- collectCoverage: true,
- coverageDirectory: 'coverage',
- testEnvironment: 'jsdom',
-};
diff --git a/package.json b/package.json
index b030e3f..d96f9c7 100644
--- a/package.json
+++ b/package.json
@@ -1,15 +1,16 @@
{
"name": "msgio",
- "version": "0.1.0",
- "description": "'postMessage' based communication library.",
+ "version": "1.0.1",
+ "description": "This library is built on 'postMessage' API to reduce painful communication codes.",
+ "keywords": ["msgio", "message", "iframe", "postMessage", "socket", "sandbox"],
"license": "MIT",
"author": "Zhixing Han ",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
"files": [
"dist",
"src"
],
- "main": "dist/index.js",
- "types": "dist/index.d.ts",
"scripts": {
"build": "npm run clean && npm run build:cjs && npm run build:umd",
"build:cjs": "tsc",
@@ -32,12 +33,10 @@
"@tsconfig/recommended": "^1.0.2",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
- "babel-jest": "^29.5.0",
"eslint": "^8.36.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-plugin-import": "^2.27.5",
- "jest": "^29.5.0",
"rimraf": "^4.4.0",
"rollup": "^3.19.1",
"typescript": "^5.0.2"