{"_id":"@alshdavid/rpc","_rev":"11-bc75cccd8385e79ac3f5c35d4faa8ad9","name":"@alshdavid/rpc","dist-tags":{"latest":"2.0.1","next":"2.0.0-4"},"versions":{"1.0.0":{"name":"@alshdavid/rpc","version":"1.0.0","author":{"name":"David Alsh"},"types":"./index.d.ts","main":"./index.js","_id":"@alshdavid/rpc@1.0.0","_nodeVersion":"14.15.5","_npmVersion":"7.9.0","dist":{"integrity":"sha512-FvvxsRdWm97hDrmj2qQH7VDWJZg19wJDuASPmlugnOFDbrmRurXAcd5G3tUuzQxH/zn5D4Y7eamZry1aDuHF4w==","shasum":"eeec3afae323b0d1619b09cd86fe36880a26087e","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-1.0.0.tgz","fileCount":10,"unpackedSize":5708,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgeDAcCRA9TVsSAnZWagAAOSYP/in3/Rax6vp/m/oSpPQ0\nsXD3IC+2Qvqo6uvexADRCin2EIr80KS8lUwOdLGpJpbsFv6/I2mF27Dwn0iE\nWG1A3ORhRynoh2FsSV/5Y13bY6JBeSpdZDK2giziwr+ltx7SXo4Ly3uQ8e5z\nC/Z9B0C66h8MdgVzzdlKzayouLBQa0iDjEszpX7a0nhQLbnS+DBhgeRMsD/X\n01su2+HyweSRKzBy4heXj7Ovf2k4g5CfPTln/on26Y7kvtqH1XW/6ChR/LBW\nuqJr9/qKm/LVq+sFn9yL20/346px5iN896x0p12AAy/qrBJR8Shi0zlt9xZv\nz+pAo3Ru2jgBf3oYjT0qb0/NjEzdVAn1lbH+YycDk9C0Z0GVLcxp8S8GJjcS\nuvprCZOGAbUJ+RSI4LutiNrXIdNG+sYp67Sgsy24nWDsT343gveawZR5zDnF\nN2yY0Ji5ZXTx+QkduYm5bAiC4Q1wHqUpwjbO5yXaCj2S/LY/1ubi0TnAiTbK\n7fZU5TT2e/kkN/eMXSq9IwUtdyjAd6fyAy3jjW6mkzbVcp1yZjyo5ePuU0Yn\nOhYkJ6/pjQ2glPycvlNJsJoD3nGxcN8EbFJft2XmZ5pgu6gLUc7WFbsQ1Pi4\nPackTuxrXjQIOKU9PFfj3WwhMVwkKLmR6k9MnaHG6oYNUu4uBFVGnzOA9cLi\nX6WN\r\n=pbhM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHQ/my/aC9XZMkjIxn97II8VC8nzsQ7al4J49urHodXNAiBRaODwQH74UlD32EG3rePAI9FTohdP4ul+j0hJpPCnjA=="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_1.0.0_1618489371649_0.6380570712494058"},"_hasShrinkwrap":false},"1.0.1":{"name":"@alshdavid/rpc","version":"1.0.1","license":"MIT","author":{"name":"David Alsh"},"types":"./index.d.ts","main":"./index.js","_id":"@alshdavid/rpc@1.0.1","_nodeVersion":"14.15.5","_npmVersion":"7.9.0","dist":{"integrity":"sha512-qAt2X2Q7ru/P8XirYdvel5Ut+iJRA6zc1c7FZymaGCNbaOf5E/smPUALyVCyPEjUZT9QhMBAk07WI/QMWqBd7w==","shasum":"04b0d72fb8d414be786489edcd62737894b2ac50","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-1.0.1.tgz","fileCount":10,"unpackedSize":5728,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgeDEfCRA9TVsSAnZWagAAaJUP/32C8dLvv9C5kIVHky42\nk/rISnEy0ufnsHGxAjrLoc9Tjfgwr/iq5+8vIjCgMhZrMl7IY7qLsl46qNQB\n/1wFQBaia4QGX76LPJx6zCZ37ctN/rWPtAabSKkqEEaorcKEqGoVbtEGiq/0\nwNIlm4zSEE3/85S5Hi57cJg4cmeCUuAfrr9Uai7yVDqQh3xoWNmW1WoP6fgm\nC97F6ZAdoQElLyq7q+TfP15ix5aNejgAq7LluktEQAUA1AeWCrjo26AS5Pih\nq2aR/SALkZwGtG5hYkdU9C+f7bv87QzIlri8ASDv6Jq83/OaRx7vPVjG8ofy\nBI9hvMDWUeICOvsZcPh+iiMTclI21YE+JIcyCEWi2rHiD/j5hMtys9TNRH4N\nBH42jOTSTWVb9VcTMdW2wzLu1P1bg9TkAhlhBqlQBUpx1LhbILTTRWJiaW9V\nt800uoSOJFHfyNDHWCl/mXw6yaGXTnirP3P11KhF58hvXxim33TaRt/HVhIv\nl6+B59qL1KI5/AVU2KWKL7iKfXuCRRCD4+VxgtoELAweztOnruaMwrrleKAJ\nWUlcizPF36rwIHeAFuKpZD3XYmYUYFywmGlLePoGlZQnHl38VBeF4Jc5tlsT\nbQvJSMSFPtmTrkjl5Zg/+Qgp/qtF3I6LlkpIHyvXo1KtoH25jEutSF8Izg69\n+JH0\r\n=zyAv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEaxSx2QRUw7l0d5oZyVV30BwIv57eJFl5zPGFVVql7cAiEA4bHl/PfoqUFOGf7slzwK/31UY+ec3v0b1eD58DDHXHw="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_1.0.1_1618489631036_0.21741280517847428"},"_hasShrinkwrap":false},"1.1.0":{"name":"@alshdavid/rpc","version":"1.1.0","license":"MIT","author":{"name":"David Alsh"},"types":"./index.d.ts","main":"./index.js","_id":"@alshdavid/rpc@1.1.0","_nodeVersion":"14.15.5","_npmVersion":"7.9.0","dist":{"integrity":"sha512-7IHPb2AEwawUuDoKXL//jOmDU68iabg5Kn3fyPRgAzcrJlnBIz7PbvCYVLiA9nZ6xyJEDEIecH/VsN21uWdMgQ==","shasum":"5b371a7a51ec001138ef9751b0613d3380e48eef","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-1.1.0.tgz","fileCount":10,"unpackedSize":5827,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgeDn0CRA9TVsSAnZWagAAsNwP+wU6wT6OYp5ulL9K2sqt\ndn3orH/y8Tjtu0Mr9h9pLQBi+Qk8cU8jUHhkFWtQeefSrku86Sf414xX/uAg\n8Z5tiObqr59vISf2ysTgars1HJmZJDSkNp45SkBV4dScLxe7Tg99agOdOx3d\neR+OVHZ2TybPH0VqCn6GPC3j7qp1KZgTKaNyb57FeILkpN+WV0YinPv0bH+5\nuEOzoiI6bxttYkZEeuC14cFg9INLwIFSApyub7BO0gZVwJIsv8GGd7G94XzN\n/p3/ISVuVBzSPyJ8GuvWbpsdE+GwB3a2t9n0py0br6II6zE0ChaVks5LJqgF\nnFMnghTZwnspufTQEoJ6Fk8bUFWkgXJ6+ZRTfsyVPKvU2s/SeICec1AkhwfQ\nw2K9n9dVNLcxIxuNbS2m2uI+TgQ1GOMLX/ATUszZ0Wk20pQluTgs9cjBwNsx\nkrNIxtuwU6koOQMLaiCwSP36GmVYwoP+cgBYsSsnc9wkBrxbpL6Sq5pOTsM6\nTwpXYqmLsVTnyG/KfwjLRLSyL7iPLtH2zoBv/QfWOyN42HQxPGlG96+wt4sV\nN8PxswFwlpM5veO9iHqrOCVqIcApub1MUtWRT/hS3t80P6Fj40Oig7+DFO3u\nxPOW60yI0gtvKON+Tm1uPMD/AgDmSAsN6Dp9A3SpaLAsvKmkohORKcv8pkYt\nMA9J\r\n=1O/v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDHbjmVv5zV5dTrsqBr33Xz1E8JozXq7VGnuNiGNhniywIhAKQzmv05WAYqcdBpoEY7CJC5g/fZ7fL6mktt7DXJJdHm"}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_1.1.0_1618491892053_0.9943674670692877"},"_hasShrinkwrap":false},"1.2.0":{"name":"@alshdavid/rpc","version":"1.2.0","license":"MIT","author":{"name":"David Alsh"},"types":"./index.d.ts","main":"./index.js","_id":"@alshdavid/rpc@1.2.0","_nodeVersion":"14.15.5","_npmVersion":"7.9.0","dist":{"integrity":"sha512-/bmHR2ZrWvy3QJuQgffmugNjnUWqtYG5oj2bA3zuI73se1EQjCjcogZag2eWfhJZSB7IfynyadnPdBtupoQULQ==","shasum":"098a6a593a55bd1c65cb96c9368a90ff83e6a238","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-1.2.0.tgz","fileCount":12,"unpackedSize":8594,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgijETCRA9TVsSAnZWagAAF+YQAJufR7mysnWe712XKPQ9\nGYe7zibTIjHnnjtxrhJqBS1XO1zwHSSbC5PT5eMv5i9GlsEkrMCd9TD38dhi\nvNQLlB5U93T3FCmHxof+NgAZH8Nm3VmU7kXVl4T7XXi39IaQrtDpiR7J2LnE\nwGtz3nJPtDI+1dHU1mbYZGpH08BjJZKd5Hz0bzvQtLyJIm6NTJL4L/9vndW1\n3uPZVvvyeSGABBRzCKx+bePGbHQodx/mGAzVALtMNwr3LeFGyBAI2Q7ihLac\ncH3UVbzk9k8eqGM0DI9G8cD5EmXVbM2X8Dwx0fRCprPJyBhur3KP1eNL7Ss2\naqxrLuRYrEqeQRhXF6KRk8XP5XjxKDOM0FRQgkfGU1qG7ezTejXIEXVABcFM\nMz5rrzWSImnjtEcoMNu3UyJelZilWhO8HcTiC8TMo6sC8vhOmnYAavfWArNV\nnZygAPh+N5sniiWQXPpo5Nx8TK7OW5rvU9icCOyWSR67sDdEUWYXUJtWv310\nbUzol5ZhCsxdO4zqRSgyXq/SEHO1Fi5bi/H9Gz/IiEqX0qScYdtA/KkoZ1Ly\nHLJ4lvOxT1tZ8M51qQI+3mzgZsspEex1YeYY+EW6idRGuFIwF9DnZXqdwlwt\n5PBXvBBsoLxmrj5yf/rzIQ2H1+jv44u02sx4o+wv10vqzxIDSlkzXm6tFHtw\nwRYh\r\n=D6bH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCTb10US0cDOoIP+An0vDkSa9HDHC6Du3s2+wwHIMYqVgIgQCfcfuriQAdHuu6k5lJsIZUHX3BAHelCWN6wAZJimT8="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_1.2.0_1619669267164_0.6339867749939503"},"_hasShrinkwrap":false},"2.0.0":{"name":"@alshdavid/rpc","version":"2.0.0","author":{"name":"David Alsh"},"license":"MIT","types":"./dist/types/index.d.ts","exports":{"./":{"require":"./.dist/cjs/","module":"./.dist/esm/","types":"./.dist/types/"}},"scripts":{"build":"npm run clean && npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:types","build:esm":"npx tsc -p tsconfig.esm.json","build:cjs":"npx tsc -p tsconfig.cjs.json","build:umd":"npx webpack --mode production","build:types":"npx tsc -p tsconfig.types.json","clean":"rm -r -f dist","test":"npx jest ./src ./tests"},"devDependencies":{"@types/jest":"^27.0.2","jest":"^27.3.1","jest-junit":"^13.0.0","rxjs":"^7.4.0","ts-jest":"^27.0.7","ts-loader":"^9.2.6","tslint":"^6.1.0","typescript":"^4.4.4","webpack":"^5.61.0","webpack-cli":"^4.9.1"},"dependencies":{"@types/lodash":"^4.14.176","lodash":"^4.17.21"},"readme":"# JavaScript RPC Library\n\n### Workers and iFrames\n\nThis library serves to be a tiny (3kb), low level RPC implementation for JavaScript that allows for the accessing of data and calling of functions/methods that live in an external context.\n\nSuch use cases are iframes and web workers. This can also be used with web sockets for cooperative server side execution.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Worker Data = { foo: () => 'bar' }\nconst ref0 = new Reference(port1)\n\nconst ref1 = ref0.property('foo')\nconst ref2 = ref1.exec()\n\nconst value = await ref2.value()\nconsole.log(value) // 'bar'\n```\n\n## Usage\n\n### Summary\n\nThis is split into two halves, the half that holds the data you want to expose - known as the `DataSource` and the half that wants to consume the data. \n\nAn example data source would be a web worker holding data that the host page wants to access. Alternatively, it could be that the web worker that wants access to the document and the host page is the data source exposing the `window` object. \n\nThe consumer accesses the data using a `Reference` which points to data in the `DataSource`. The consumer can walk up an object to find data or trigger methods.\n\n#### Data Source\n\nFrom your Data Source (iframe, worker), expose your data\n```typescript\nimport { DataSource } from '@alshdavid/rpc'\n\nconst data = { foo: 'bar' }\nconst dataSource = new DataSource(port2, data)\n```\n\n#### Consumer\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Connect to the DataSource and get your root reference\nconst ref0 = new Reference(port1)\n\n// Crawl the tree\nconst ref1 = ref0.property('foo')\n\n// Grab the value at the reference point\nconst value = await ref1.value()\n```\n\n#### Functions, Methods, Callbacks\n\nFunctions, methods along with callback arguments. Yes, you can send function accepting function accepting functions over a serialized boundary.\n\n```typescript\n// Data = () => 'Hello World'\nconst resultRef = await ref0.exec()\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (value) => value\nconst resultRef = await ref0.exec('Hello World')\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (callback) => void\nawait ref0.exec(() => {\n  console.log('callback')\n})\n```\n\n```typescript\n// Data = (callback: (next: () => void) => void) => void\nawait ref0.exec(async nextRef => {\n  await nextRef.exec()\n})\n```\n\n#### Exceptions\n\nErrors thrown in the data source are propagated to the consumer through the reference. The errors are references to the error in the data source.\n\n```typescript\ntry {\n  await ref0.exec()\n} catch (errorRef) {\n  console.log(await errorRef.reference.property('message').value())\n}\n```\n\n#### Observed/Realized values vs Traversal\n\nValues are not accessed until `.exec()` or `.value()` are run. Traversing an object using `.property()` will not incur a communication cost.\n\n```typescript\n// Data = { foo: { bar: { foobar: 'foobar' }}}\n\nconst ref1 = await ref0.property('foo') // Create reference with path\nconst ref2 = await ref1.property('bar', 'foobar') // Build it up\n\nconst foobar = await ref2.value() // Now get the value there \n```\n\n#### Memory Management\n\nThere might be some improvements I can make here with time, but for now certain calls will incur a memory cost as certain values are stored on either side.\n\nThings like function return values, callback function values, callback parameters, are all cached and must be manually purged when no longer needed\n\n```typescript\n// Data = () => 'Hello World'\n\nconst returnValueRef = await ref0.exec()\nconsole.log(await returnValueRef.value()) // 'Hello World'\n\nawait returnValueRef.release() // Purge the cache for this return value\n\nconsole.log(await returnValueRef.value()) // undefined\n```\n\n```typescript\n// Data = (callback: (foo, bar) => void) => void\n\nconst returnValueRef = await ref0.exec(async (fooRef, barRef) => {\n  console.log(await fooRef.value()) // 'foo'\n  console.log(await barRef.value()) // 'bar'\n})\n\nref0.release() // This will purge the 'foo' and 'bar' variables\n```\n\n### MessagePorts\n\nThe base API uses the browser `MessagePort` as the communication interface, so transfer your ports between your entities and you're good to go.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\nconst { port1, port2 } = new MessageChannel()\n\nconst iframe = document.createElement('iframe')\niframe.src = 'https://my-external-app'\niframe.contentWindow.postMessage('ports', '*', [port2])\n\nconst ref0 = new Reference(port1)\nport1.start()\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","readmeFilename":"README.md","gitHead":"43db5b93def2d2e6a10b041bbb65e565b6a8e258","description":"### Workers and iFrames","_id":"@alshdavid/rpc@2.0.0","_nodeVersion":"16.13.0","_npmVersion":"8.1.1","dist":{"integrity":"sha512-yXDnGaBGRs/2O7SMGAExr6hcQ9UohVKDQXsF2SGailv8r4MUYZ0RCkCqDYPotNM8Ue8X0mubfOYSY0XZmkrqkw==","shasum":"741785f7994e94f564261facd08355a8629f0279","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-2.0.0.tgz","fileCount":65,"unpackedSize":68979,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBvd6tXwJ69c2NX4CyeDujAav5BppX/obVeOhQxg9ObFAiEA+LG1cAwcihr+MubQMi+OQvRXvGHvT2YZoYZ6nLhCrhw="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_2.0.0_1635836435474_0.8908260424631982"},"_hasShrinkwrap":false},"2.0.0-1":{"name":"@alshdavid/rpc","version":"2.0.0-1","author":{"name":"David Alsh"},"license":"MIT","types":"./dist/types/index.d.ts","exports":{"./":{"require":"./.dist/cjs/","module":"./.dist/esm/","types":"./.dist/types/"}},"scripts":{"build":"npm run clean && npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:types","build:esm":"npx tsc -p tsconfig.esm.json","build:cjs":"npx tsc -p tsconfig.cjs.json","build:umd":"npx webpack --mode production","build:types":"npx tsc -p tsconfig.types.json","clean":"rm -r -f dist","test":"npx jest ./src ./tests"},"devDependencies":{"@types/jest":"^27.0.2","jest":"^27.3.1","jest-junit":"^13.0.0","rxjs":"^7.4.0","ts-jest":"^27.0.7","ts-loader":"^9.2.6","tslint":"^6.1.0","typescript":"^4.4.4","webpack":"^5.61.0","webpack-cli":"^4.9.1"},"dependencies":{"@types/lodash":"^4.14.176","lodash":"^4.17.21"},"readme":"# JavaScript RPC Library\n\n### Workers and iFrames\n\nThis library serves to be a tiny (3kb), low level RPC implementation for JavaScript that allows for the accessing of data and calling of functions/methods that live in an external context.\n\nSuch use cases are iframes and web workers. This can also be used with web sockets for cooperative server side execution.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Worker Data = { foo: () => 'bar' }\nconst ref0 = new Reference(port1)\n\nconst ref1 = ref0.property('foo')\nconst ref2 = ref1.exec()\n\nconst value = await ref2.value()\nconsole.log(value) // 'bar'\n```\n\n## Usage\n\n### Summary\n\nThis is split into two halves, the half that holds the data you want to expose - known as the `DataSource` and the half that wants to consume the data. \n\nAn example data source would be a web worker holding data that the host page wants to access. Alternatively, it could be that the web worker that wants access to the document and the host page is the data source exposing the `window` object. \n\nThe consumer accesses the data using a `Reference` which points to data in the `DataSource`. The consumer can walk up an object to find data or trigger methods.\n\n#### Data Source\n\nFrom your Data Source (iframe, worker), expose your data\n```typescript\nimport { DataSource } from '@alshdavid/rpc'\n\nconst data = { foo: 'bar' }\nconst dataSource = new DataSource(port2, data)\n```\n\n#### Consumer\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Connect to the DataSource and get your root reference\nconst ref0 = new Reference(port1)\n\n// Crawl the tree\nconst ref1 = ref0.property('foo')\n\n// Grab the value at the reference point\nconst value = await ref1.value()\n```\n\n#### Functions, Methods, Callbacks\n\nFunctions, methods along with callback arguments. Yes, you can send function accepting function accepting functions over a serialized boundary.\n\n```typescript\n// Data = () => 'Hello World'\nconst resultRef = await ref0.exec()\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (value) => value\nconst resultRef = await ref0.exec('Hello World')\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (callback) => void\nawait ref0.exec(() => {\n  console.log('callback')\n})\n```\n\n```typescript\n// Data = (callback: (next: () => void) => void) => void\nawait ref0.exec(async nextRef => {\n  await nextRef.exec()\n})\n```\n\n#### Exceptions\n\nErrors thrown in the data source are propagated to the consumer through the reference. The errors are references to the error in the data source.\n\n```typescript\ntry {\n  await ref0.exec()\n} catch (errorRef) {\n  console.log(await errorRef.reference.property('message').value())\n}\n```\n\n#### Observed/Realized values vs Traversal\n\nValues are not accessed until `.exec()` or `.value()` are run. Traversing an object using `.property()` will not incur a communication cost.\n\n```typescript\n// Data = { foo: { bar: { foobar: 'foobar' }}}\n\nconst ref1 = await ref0.property('foo') // Create reference with path\nconst ref2 = await ref1.property('bar', 'foobar') // Build it up\n\nconst foobar = await ref2.value() // Now get the value there \n```\n\n#### Memory Management\n\nThere might be some improvements I can make here with time, but for now certain calls will incur a memory cost as certain values are stored on either side.\n\nThings like function return values, callback function values, callback parameters, are all cached and must be manually purged when no longer needed\n\n```typescript\n// Data = () => 'Hello World'\n\nconst returnValueRef = await ref0.exec()\nconsole.log(await returnValueRef.value()) // 'Hello World'\n\nawait returnValueRef.release() // Purge the cache for this return value\n\nconsole.log(await returnValueRef.value()) // undefined\n```\n\n```typescript\n// Data = (callback: (foo, bar) => void) => void\n\nconst returnValueRef = await ref0.exec(async (fooRef, barRef) => {\n  console.log(await fooRef.value()) // 'foo'\n  console.log(await barRef.value()) // 'bar'\n})\n\nref0.release() // This will purge the 'foo' and 'bar' variables\n```\n\n### MessagePorts\n\nThe base API uses the browser `MessagePort` as the communication interface, so transfer your ports between your entities and you're good to go.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\nconst { port1, port2 } = new MessageChannel()\n\nconst iframe = document.createElement('iframe')\niframe.src = 'https://my-external-app'\niframe.contentWindow.postMessage('ports', '*', [port2])\n\nconst ref0 = new Reference(port1)\nport1.start()\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","readmeFilename":"README.md","gitHead":"43db5b93def2d2e6a10b041bbb65e565b6a8e258","description":"### Workers and iFrames","_id":"@alshdavid/rpc@2.0.0-1","_nodeVersion":"16.13.0","_npmVersion":"8.1.1","dist":{"integrity":"sha512-vdQMyHkK/cZecf03HQpmxHwm9ph6IBd2ziMzRnUlkDpNwD29nGdHPEfVpVXzes/8QjPYooozkRQ6S++/zRtfIA==","shasum":"447853038336b600a92f1c423b923fd30bb688d0","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-2.0.0-1.tgz","fileCount":52,"unpackedSize":58930,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH7G4ipqTEzuqBoi6EYqSVigckY3JF7HQ9ukwWNhVI8yAiEAoJ7zwk108MiDGvJxT4c8LZrS83JwhPekxQvpy10NPPc="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_2.0.0-1_1635836489432_0.5077534272141453"},"_hasShrinkwrap":false},"2.0.0-2":{"name":"@alshdavid/rpc","version":"2.0.0-2","author":{"name":"David Alsh"},"license":"MIT","types":"./dist/types/index.d.ts","exports":{"./":{"require":"./.dist/cjs/","module":"./.dist/esm/","types":"./.dist/types/"}},"scripts":{"build":"npm run clean && npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:types","build:esm":"npx tsc -p tsconfig.esm.json","build:cjs":"npx tsc -p tsconfig.cjs.json","build:umd":"npx webpack --mode production","build:types":"npx tsc -p tsconfig.types.json","clean":"rm -r -f dist","test":"npx jest ./src ./tests"},"devDependencies":{"@types/jest":"^27.0.2","jest":"^27.3.1","rxjs":"^7.4.0","ts-jest":"^27.0.7","ts-loader":"^9.2.6","typescript":"^4.4.4","webpack":"^5.61.0","webpack-cli":"^4.9.1"},"readme":"# JavaScript RPC Library\n\n### Workers and iFrames\n\nThis library serves to be a tiny (3kb), low level RPC implementation for JavaScript that allows for the accessing of data and calling of functions/methods that live in an external context.\n\nSuch use cases are iframes and web workers. This can also be used with web sockets for cooperative server side execution.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Worker Data = { foo: () => 'bar' }\nconst ref0 = new Reference(port1)\n\nconst ref1 = ref0.property('foo')\nconst ref2 = ref1.exec()\n\nconst value = await ref2.value()\nconsole.log(value) // 'bar'\n```\n\n## Usage\n\n### Summary\n\nThis is split into two halves, the half that holds the data you want to expose - known as the `DataSource` and the half that wants to consume the data. \n\nAn example data source would be a web worker holding data that the host page wants to access. Alternatively, it could be that the web worker that wants access to the document and the host page is the data source exposing the `window` object. \n\nThe consumer accesses the data using a `Reference` which points to data in the `DataSource`. The consumer can walk up an object to find data or trigger methods.\n\n#### Data Source\n\nFrom your Data Source (iframe, worker), expose your data\n```typescript\nimport { DataSource } from '@alshdavid/rpc'\n\nconst data = { foo: 'bar' }\nconst dataSource = new DataSource(port2, data)\n```\n\n#### Consumer\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Connect to the DataSource and get your root reference\nconst ref0 = new Reference(port1)\n\n// Crawl the tree\nconst ref1 = ref0.property('foo')\n\n// Grab the value at the reference point\nconst value = await ref1.value()\n```\n\n#### Functions, Methods, Callbacks\n\nFunctions, methods along with callback arguments. Yes, you can send function accepting function accepting functions over a serialized boundary.\n\n```typescript\n// Data = () => 'Hello World'\nconst resultRef = await ref0.exec()\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (value) => value\nconst resultRef = await ref0.exec('Hello World')\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (callback) => void\nawait ref0.exec(() => {\n  console.log('callback')\n})\n```\n\n```typescript\n// Data = (callback: (next: () => void) => void) => void\nawait ref0.exec(async nextRef => {\n  await nextRef.exec()\n})\n```\n\n#### Exceptions\n\nErrors thrown in the data source are propagated to the consumer through the reference. The errors are references to the error in the data source.\n\n```typescript\ntry {\n  await ref0.exec()\n} catch (errorRef) {\n  console.log(await errorRef.reference.property('message').value())\n}\n```\n\n#### Observed/Realized values vs Traversal\n\nValues are not accessed until `.exec()` or `.value()` are run. Traversing an object using `.property()` will not incur a communication cost.\n\n```typescript\n// Data = { foo: { bar: { foobar: 'foobar' }}}\n\nconst ref1 = await ref0.property('foo') // Create reference with path\nconst ref2 = await ref1.property('bar', 'foobar') // Build it up\n\nconst foobar = await ref2.value() // Now get the value there \n```\n\n#### Memory Management\n\nThere might be some improvements I can make here with time, but for now certain calls will incur a memory cost as certain values are stored on either side.\n\nThings like function return values, callback function values, callback parameters, are all cached and must be manually purged when no longer needed\n\n```typescript\n// Data = () => 'Hello World'\n\nconst returnValueRef = await ref0.exec()\nconsole.log(await returnValueRef.value()) // 'Hello World'\n\nawait returnValueRef.release() // Purge the cache for this return value\n\nconsole.log(await returnValueRef.value()) // undefined\n```\n\n```typescript\n// Data = (callback: (foo, bar) => void) => void\n\nconst returnValueRef = await ref0.exec(async (fooRef, barRef) => {\n  console.log(await fooRef.value()) // 'foo'\n  console.log(await barRef.value()) // 'bar'\n})\n\nref0.release() // This will purge the 'foo' and 'bar' variables\n```\n\n### MessagePorts\n\nThe base API uses the browser `MessagePort` as the communication interface, so transfer your ports between your entities and you're good to go.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\nconst { port1, port2 } = new MessageChannel()\n\nconst iframe = document.createElement('iframe')\niframe.src = 'https://my-external-app'\niframe.contentWindow.postMessage('ports', '*', [port2])\n\nconst ref0 = new Reference(port1)\nport1.start()\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","readmeFilename":"README.md","gitHead":"43db5b93def2d2e6a10b041bbb65e565b6a8e258","description":"### Workers and iFrames","_id":"@alshdavid/rpc@2.0.0-2","_nodeVersion":"16.13.0","_npmVersion":"8.1.1","dist":{"integrity":"sha512-WWl03GEiCA2VGZmKAjrcug0WH0U08Lo4Ln0EHKddST3CvxHBBlGbqbS8oI1WDSgr0PRM5GC9SvpqtmEKQp/rvg==","shasum":"cb40a2d54f618cb357b0b1e0b66ddd61022aa8b1","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-2.0.0-2.tgz","fileCount":61,"unpackedSize":71691,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC5iFHk4Va2IvNaqUQIjmejE1qnxfJwxRkrdBKMulPFXgIhAK+P6fpJ2uQ10sAX2/M5Xdz2MAbJYuSYGoA3T3EBjT2Y"}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_2.0.0-2_1635837666298_0.43952043454428935"},"_hasShrinkwrap":false},"2.0.0-3":{"name":"@alshdavid/rpc","version":"2.0.0-3","author":{"name":"David Alsh"},"license":"MIT","types":"./dist/types/index.d.ts","exports":{"./":{"require":"./.dist/cjs/","module":"./.dist/esm/","types":"./.dist/types/"}},"scripts":{"build":"npm run clean && npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:types","build:esm":"npx tsc -p tsconfig.esm.json","build:cjs":"npx tsc -p tsconfig.cjs.json","build:umd":"npx webpack --mode production","build:types":"npx tsc -p tsconfig.types.json","clean":"rm -r -f dist","test":"npx jest ./src ./tests"},"devDependencies":{"@types/jest":"^27.0.2","jest":"^27.3.1","rxjs":"^7.4.0","ts-jest":"^27.0.7","ts-loader":"^9.2.6","typescript":"^4.4.4","webpack":"^5.61.0","webpack-cli":"^4.9.1"},"gitHead":"6e66936570809b3375ddb976a4799483d0f73ac4","readme":"# JavaScript RPC Library\n\n### Workers and iFrames\n\nThis library serves to be a tiny (3kb), low level RPC implementation for JavaScript that allows for the accessing of data and calling of functions/methods that live in an external context.\n\nSuch use cases are iframes and web workers. This can also be used with web sockets for cooperative server side execution.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Worker Data = { foo: () => 'bar' }\nconst ref0 = new Reference(port1)\n\nconst ref1 = ref0.property('foo')\nconst ref2 = ref1.exec()\n\nconst value = await ref2.value()\nconsole.log(value) // 'bar'\n```\n\n## Usage\n\n### Summary\n\nThis is split into two halves, the half that holds the data you want to expose - known as the `DataSource` and the half that wants to consume the data. \n\nAn example data source would be a web worker holding data that the host page wants to access. Alternatively, it could be that the web worker that wants access to the document and the host page is the data source exposing the `window` object. \n\nThe consumer accesses the data using a `Reference` which points to data in the `DataSource`. The consumer can walk up an object to find data or trigger methods.\n\n#### Data Source\n\nFrom your Data Source (iframe, worker), expose your data\n```typescript\nimport { DataSource } from '@alshdavid/rpc'\n\nconst data = { foo: 'bar' }\nconst dataSource = new DataSource(port2, data)\n```\n\n#### Consumer\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Connect to the DataSource and get your root reference\nconst ref0 = new Reference(port1)\n\n// Crawl the tree\nconst ref1 = ref0.property('foo')\n\n// Grab the value at the reference point\nconst value = await ref1.value()\n```\n\n#### Functions, Methods, Callbacks\n\nFunctions, methods along with callback arguments. Yes, you can send function accepting function accepting functions over a serialized boundary.\n\n```typescript\n// Data = () => 'Hello World'\nconst resultRef = await ref0.exec()\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (value) => value\nconst resultRef = await ref0.exec('Hello World')\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (callback) => void\nawait ref0.exec(() => {\n  console.log('callback')\n})\n```\n\n```typescript\n// Data = (callback: (next: () => void) => void) => void\nawait ref0.exec(async nextRef => {\n  await nextRef.exec()\n})\n```\n\n#### Exceptions\n\nErrors thrown in the data source are propagated to the consumer through the reference. The errors are references to the error in the data source.\n\n```typescript\ntry {\n  await ref0.exec()\n} catch (errorRef) {\n  console.log(await errorRef.reference.property('message').value())\n}\n```\n\n#### Observed/Realized values vs Traversal\n\nValues are not accessed until `.exec()` or `.value()` are run. Traversing an object using `.property()` will not incur a communication cost.\n\n```typescript\n// Data = { foo: { bar: { foobar: 'foobar' }}}\n\nconst ref1 = await ref0.property('foo') // Create reference with path\nconst ref2 = await ref1.property('bar', 'foobar') // Build it up\n\nconst foobar = await ref2.value() // Now get the value there \n```\n\n#### Memory Management\n\nThere might be some improvements I can make here with time, but for now certain calls will incur a memory cost as certain values are stored on either side.\n\nThings like function return values, callback function values, callback parameters, are all cached and must be manually purged when no longer needed\n\n```typescript\n// Data = () => 'Hello World'\n\nconst returnValueRef = await ref0.exec()\nconsole.log(await returnValueRef.value()) // 'Hello World'\n\nawait returnValueRef.release() // Purge the cache for this return value\n\nconsole.log(await returnValueRef.value()) // undefined\n```\n\n```typescript\n// Data = (callback: (foo, bar) => void) => void\n\nconst returnValueRef = await ref0.exec(async (fooRef, barRef) => {\n  console.log(await fooRef.value()) // 'foo'\n  console.log(await barRef.value()) // 'bar'\n})\n\nref0.release() // This will purge the 'foo' and 'bar' variables\n```\n\n### MessagePorts\n\nThe base API uses the browser `MessagePort` as the communication interface, so transfer your ports between your entities and you're good to go.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\nconst { port1, port2 } = new MessageChannel()\n\nconst iframe = document.createElement('iframe')\niframe.src = 'https://my-external-app'\niframe.contentWindow.postMessage('ports', '*', [port2])\n\nconst ref0 = new Reference(port1)\nport1.start()\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","readmeFilename":"README.md","description":"### Workers and iFrames","_id":"@alshdavid/rpc@2.0.0-3","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-JBWUL1VOD+TSTtM+JGsBH3uG/4YhQnRKxtniKNHvz0YP0h6uPSewOqto1OssKFn9BsafBf+G6tQvGqapzjtKjw==","shasum":"d64979b699d4604968f29dee94129f261ce70ded","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-2.0.0-3.tgz","fileCount":61,"unpackedSize":55910,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDDkXOwUNdf+lPUxDeSttLORb8HaUbofUhXTQQaBtjzuAIgdptJQhf3EOM/ICR9UvArQsv7ZatT0ZJChreVlkmWHkY="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_2.0.0-3_1635842967346_0.1886421590618932"},"_hasShrinkwrap":false},"2.0.0-4":{"name":"@alshdavid/rpc","version":"2.0.0-4","author":{"name":"David Alsh"},"license":"MIT","types":"./dist/types/index.d.ts","exports":{"./":{"require":"./.dist/cjs/","module":"./.dist/esm/","types":"./.dist/types/"}},"scripts":{"build":"npm run clean && npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:types","build:esm":"npx tsc -p tsconfig.esm.json","build:cjs":"npx tsc -p tsconfig.cjs.json","build:umd":"npx webpack --mode production","build:types":"npx tsc -p tsconfig.types.json","clean":"rm -r -f dist","test":"npx jest ./src ./tests"},"devDependencies":{"@types/jest":"^27.0.2","jest":"^27.3.1","rxjs":"^7.4.0","ts-jest":"^27.0.7","ts-loader":"^9.2.6","typescript":"^4.4.4","webpack":"^5.61.0","webpack-cli":"^4.9.1"},"gitHead":"1be5eb707419e6354072bc0f514f3eb7c610fd3e","readme":"# JavaScript RPC Library\n\n### Workers and iFrames\n\nThis library serves to be a tiny (3kb), low level RPC implementation for JavaScript that allows for the accessing of data and calling of functions/methods that live in an external context.\n\nSuch use cases are iframes and web workers. This can also be used with web sockets for cooperative server side execution.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Worker Data = { foo: () => 'bar' }\nconst ref0 = new Reference(port1)\n\nconst ref1 = ref0.property('foo')\nconst ref2 = ref1.exec()\n\nconst value = await ref2.value()\nconsole.log(value) // 'bar'\n```\n\n## Usage\n\n### Summary\n\nThis is split into two halves, the half that holds the data you want to expose - known as the `DataSource` and the half that wants to consume the data. \n\nAn example data source would be a web worker holding data that the host page wants to access. Alternatively, it could be that the web worker that wants access to the document and the host page is the data source exposing the `window` object. \n\nThe consumer accesses the data using a `Reference` which points to data in the `DataSource`. The consumer can walk up an object to find data or trigger methods.\n\n#### Data Source\n\nFrom your Data Source (iframe, worker), expose your data\n```typescript\nimport { DataSource } from '@alshdavid/rpc'\n\nconst data = { foo: 'bar' }\nconst dataSource = new DataSource(port2, data)\n```\n\n#### Consumer\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Connect to the DataSource and get your root reference\nconst ref0 = new Reference(port1)\n\n// Crawl the tree\nconst ref1 = ref0.property('foo')\n\n// Grab the value at the reference point\nconst value = await ref1.value()\n```\n\n#### Functions, Methods, Callbacks\n\nFunctions, methods along with callback arguments. Yes, you can send function accepting function accepting functions over a serialized boundary.\n\n```typescript\n// Data = () => 'Hello World'\nconst resultRef = await ref0.exec()\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (value) => value\nconst resultRef = await ref0.exec('Hello World')\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (callback) => void\nawait ref0.exec(() => {\n  console.log('callback')\n})\n```\n\n```typescript\n// Data = (callback: (next: () => void) => void) => void\nawait ref0.exec(async nextRef => {\n  await nextRef.exec()\n})\n```\n\n#### Exceptions\n\nErrors thrown in the data source are propagated to the consumer through the reference. The errors are references to the error in the data source.\n\n```typescript\ntry {\n  await ref0.exec()\n} catch (errorRef) {\n  console.log(await errorRef.reference.property('message').value())\n}\n```\n\n#### Observed/Realized values vs Traversal\n\nValues are not accessed until `.exec()` or `.value()` are run. Traversing an object using `.property()` will not incur a communication cost.\n\n```typescript\n// Data = { foo: { bar: { foobar: 'foobar' }}}\n\nconst ref1 = await ref0.property('foo') // Create reference with path\nconst ref2 = await ref1.property('bar', 'foobar') // Build it up\n\nconst foobar = await ref2.value() // Now get the value there \n```\n\n#### Memory Management\n\nThere might be some improvements I can make here with time, but for now certain calls will incur a memory cost as certain values are stored on either side.\n\nThings like function return values, callback function values, callback parameters, are all cached and must be manually purged when no longer needed\n\n```typescript\n// Data = () => 'Hello World'\n\nconst returnValueRef = await ref0.exec()\nconsole.log(await returnValueRef.value()) // 'Hello World'\n\nawait returnValueRef.release() // Purge the cache for this return value\n\nconsole.log(await returnValueRef.value()) // undefined\n```\n\n```typescript\n// Data = (callback: (foo, bar) => void) => void\n\nconst returnValueRef = await ref0.exec(async (fooRef, barRef) => {\n  console.log(await fooRef.value()) // 'foo'\n  console.log(await barRef.value()) // 'bar'\n})\n\nref0.release() // This will purge the 'foo' and 'bar' variables\n```\n\n### MessagePorts\n\nThe base API uses the browser `MessagePort` as the communication interface, so transfer your ports between your entities and you're good to go.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\nconst { port1, port2 } = new MessageChannel()\n\nconst iframe = document.createElement('iframe')\niframe.src = 'https://my-external-app'\niframe.contentWindow.postMessage('ports', '*', [port2])\n\nconst ref0 = new Reference(port1)\nport1.start()\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","readmeFilename":"README.md","description":"### Workers and iFrames","_id":"@alshdavid/rpc@2.0.0-4","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-dDV8Ct4c3T4XhcDajxf8ltGuLMu5QYIRXvIAbxOBZ642A36c/c5WOUA2fhUBCwTGi37K1F+vqXTrIrPkWxX2SQ==","shasum":"1a3630bf5175b30a91b36108164837d971496810","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-2.0.0-4.tgz","fileCount":61,"unpackedSize":59188,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDs4kD74KLS/AhTGtynmZ1tXOOncv0czlyMFxuvMa9kNwIhALG2VBD/QylDfyGseedc1+k0LB1F33lah7mG2UNdcaeq"}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_2.0.0-4_1635844994252_0.6690760393491766"},"_hasShrinkwrap":false},"2.0.1":{"name":"@alshdavid/rpc","version":"2.0.1","author":{"name":"David Alsh"},"license":"MIT","types":"./dist/types/index.d.ts","exports":{"./":{"require":"./.dist/cjs/","module":"./.dist/esm/","types":"./.dist/types/"}},"scripts":{"build":"npm run clean && npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:types","build:esm":"npx tsc -p tsconfig.esm.json","build:cjs":"npx tsc -p tsconfig.cjs.json","build:umd":"npx webpack --mode production","build:types":"npx tsc -p tsconfig.types.json","clean":"rm -r -f dist","test":"npx jest ./src ./tests"},"devDependencies":{"@types/jest":"^27.0.2","jest":"^27.3.1","rxjs":"^7.4.0","ts-jest":"^27.0.7","ts-loader":"^9.2.6","typescript":"^4.4.4","webpack":"^5.61.0","webpack-cli":"^4.9.1"},"gitHead":"fdeb6a02d21c45ab466e657d705bd238fa6f26cc","description":"### Workers and iFrames","_id":"@alshdavid/rpc@2.0.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-A4jPP0gDBTjho3CQFy1wMefF0bcE9VCvigvQ85SRb/OesaImN8Fd6G6G782zpCjeDqM3NDTKbuYgudIhccvYTw==","shasum":"2eb0c4bcd78e1501779be2edbe89af5ef2d8fa66","tarball":"https://registry.npmjs.org/@alshdavid/rpc/-/rpc-2.0.1.tgz","fileCount":61,"unpackedSize":59801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhzFDpCRA9TVsSAnZWagAAfAEQAJo5VeQM0G3+NeyovvXW\nNTRgZVtoYFYm8avpPs+1TVxVmJ9l1NsAW06FiW8lYkhxYOatorvKFCtHpe/5\nqNfZjlbQX5pOCXRboceGRxr6TxU9ogs3i2DyvHf/QUpK0V8QZ52VyNjxbOrs\nFjEGv7f7VfhbwFE8Ii0p0eO4o3/eoWjbmwdAFiNySVUpH7TPCIxSQAglZR9g\nKf3YfUtSo6VLjeFgp76/Qa8cU6z70QNyQ8KWjEoarblA19FpnsGxyQhCYT4Z\nPaim2W3fvQ2QBnVmaaPse0tkhnE051hlb9J/vYY1DjHKvJ7Y+eR94CsLhCL9\nRkcMjKfhDrkUr1dh7POFjJ/6xPfHLX3tkPFCkaFYJTUFl+H3BQOt4u2jbFvw\nNCiOilSNRVESTVMqFL8nF3dqqlKFBn4zLq/4pUOREHcYOCDgzzvirSU14lcU\n49Rl19VRCsP24bri8aa3fTQ+RbFFX6UlMozpiux1V9KLeyuMJJJuGMqI8Ez1\nuQUI2OX69h0IrvZZYwyTJ7QJz/0eBi5/pu3w576xE41mlRdfghPDuXZ7ZRz8\nvPu9Iwx6Dzmm66FdStOI0ujw36L5z511a7RP7r673Tgu71LTbXYHbyuAqeXs\nPmOtaUJT4UpnqXOYPOrFjAKj31fQdgVRNEkApCgFT4zLOHQBCI6/oG/Da6dF\nluHu\r\n=onqF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC2wDToVI6CH6YV9p9tUfci6e31Yv6GUWntuwCVQmqAvgIgYDPoqLS7F8JfVSL8DudAxqGmclRVUJgRgWGEAZnHoMk="}]},"_npmUser":{"name":"alshdavid","email":"alshdavid@gmail.com"},"directories":{},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/rpc_2.0.1_1635856160146_0.42093279204045286"},"_hasShrinkwrap":false}},"time":{"created":"2021-04-15T12:22:51.584Z","1.0.0":"2021-04-15T12:22:51.802Z","modified":"2022-04-04T13:38:58.561Z","1.0.1":"2021-04-15T12:27:11.172Z","1.1.0":"2021-04-15T13:04:52.160Z","1.2.0":"2021-04-29T04:07:47.283Z","2.0.0":"2021-11-02T07:00:35.908Z","2.0.0-1":"2021-11-02T07:01:29.556Z","2.0.0-2":"2021-11-02T07:21:06.459Z","2.0.0-3":"2021-11-02T08:49:27.473Z","2.0.0-4":"2021-11-02T09:23:14.383Z","2.0.1":"2021-11-02T12:29:20.310Z"},"maintainers":[{"name":"alshdavid","email":"alshdavid@gmail.com"}],"author":{"name":"David Alsh"},"readme":"# JavaScript RPC Library\n\n### Workers and iFrames\n\nThis library serves to be a tiny (3kb), low level RPC implementation for JavaScript that allows for the accessing of data and calling of functions/methods that live in an external context.\n\nSuch use cases are iframes and web workers. This can also be used with web sockets for cooperative server side execution.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Worker Data = { foo: () => 'bar' }\nconst ref0 = new Reference(port1)\n\nconst ref1 = ref0.property('foo')\nconst ref2 = ref1.exec()\n\nconst value = await ref2.value()\nconsole.log(value) // 'bar'\n```\n\n## Usage\n\n### Summary\n\nThis is split into two halves, the half that holds the data you want to expose - known as the `DataSource` and the half that wants to consume the data. \n\nAn example data source would be a web worker holding data that the host page wants to access. Alternatively, it could be that the web worker that wants access to the document and the host page is the data source exposing the `window` object. \n\nThe consumer accesses the data using a `Reference` which points to data in the `DataSource`. The consumer can walk up an object to find data or trigger methods.\n\n#### Data Source\n\nFrom your Data Source (iframe, worker), expose your data\n```typescript\nimport { DataSource } from '@alshdavid/rpc'\n\nconst data = { foo: 'bar' }\nconst dataSource = new DataSource(port2, data)\n```\n\n#### Consumer\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\n// Connect to the DataSource and get your root reference\nconst ref0 = new Reference(port1)\n\n// Crawl the tree\nconst ref1 = ref0.property('foo')\n\n// Grab the value at the reference point\nconst value = await ref1.value()\n```\n\n#### Functions, Methods, Callbacks\n\nFunctions, methods along with callback arguments. Yes, you can send function accepting function accepting functions over a serialized boundary.\n\n```typescript\n// Data = () => 'Hello World'\nconst resultRef = await ref0.exec()\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (value) => value\nconst resultRef = await ref0.exec('Hello World')\nconst value = await resultRef.value()\n\nconsole.log(value) // 'Hello World'\n```\n\n```typescript\n// Data = (callback) => void\nawait ref0.exec(() => {\n  console.log('callback')\n})\n```\n\n```typescript\n// Data = (callback: (next: () => void) => void) => void\nawait ref0.exec(async nextRef => {\n  await nextRef.exec()\n})\n```\n\n#### Exceptions\n\nErrors thrown in the data source are propagated to the consumer through the reference. The errors are references to the error in the data source.\n\n```typescript\ntry {\n  await ref0.exec()\n} catch (errorRef) {\n  console.log(await errorRef.reference.property('message').value())\n}\n```\n\n#### Observed/Realized values vs Traversal\n\nValues are not accessed until `.exec()` or `.value()` are run. Traversing an object using `.property()` will not incur a communication cost.\n\n```typescript\n// Data = { foo: { bar: { foobar: 'foobar' }}}\n\nconst ref1 = await ref0.property('foo') // Create reference with path\nconst ref2 = await ref1.property('bar', 'foobar') // Build it up\n\nconst foobar = await ref2.value() // Now get the value there \n```\n\n#### Memory Management\n\nThere might be some improvements I can make here with time, but for now certain calls will incur a memory cost as certain values are stored on either side.\n\nThings like function return values, callback function values, callback parameters, are all cached and must be manually purged when no longer needed\n\n```typescript\n// Data = () => 'Hello World'\n\nconst returnValueRef = await ref0.exec()\nconsole.log(await returnValueRef.value()) // 'Hello World'\n\nawait returnValueRef.release() // Purge the cache for this return value\n\nconsole.log(await returnValueRef.value()) // undefined\n```\n\n```typescript\n// Data = (callback: (foo, bar) => void) => void\n\nconst returnValueRef = await ref0.exec(async (fooRef, barRef) => {\n  console.log(await fooRef.value()) // 'foo'\n  console.log(await barRef.value()) // 'bar'\n})\n\nref0.release() // This will purge the 'foo' and 'bar' variables\n```\n\n### MessagePorts\n\nThe base API uses the browser `MessagePort` as the communication interface, so transfer your ports between your entities and you're good to go.\n\n```typescript\nimport { Reference } from '@alshdavid/rpc'\n\nconst { port1, port2 } = new MessageChannel()\n\nconst iframe = document.createElement('iframe')\niframe.src = 'https://my-external-app'\niframe.contentWindow.postMessage('ports', '*', [port2])\n\nconst ref0 = new Reference(port1)\nport1.start()\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","readmeFilename":"README.md","license":"MIT","description":"### Workers and iFrames"}