{"id":21571137,"url":"https://github.com/livepersoninc/chronosjs","last_synced_at":"2025-04-10T14:20:32.039Z","repository":{"id":32442812,"uuid":"36021083","full_name":"LivePersonInc/chronosjs","owner":"LivePersonInc","description":"JS Channels (Events / Commands / Reqest-Response / Courier) Mechanism","archived":false,"fork":false,"pushed_at":"2017-06-01T06:25:06.000Z","size":292,"stargazers_count":34,"open_issues_count":1,"forks_count":5,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-24T13:01:39.254Z","etag":null,"topics":["chronos","commands","communication","courier","events","postmessage","postmessage-api","reqres","request","response"],"latest_commit_sha":null,"homepage":"http://livepersoninc.github.io/chronosjs/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LivePersonInc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-21T15:30:44.000Z","updated_at":"2023-09-08T16:57:54.000Z","dependencies_parsed_at":"2022-07-22T08:22:13.450Z","dependency_job_id":null,"html_url":"https://github.com/LivePersonInc/chronosjs","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LivePersonInc%2Fchronosjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LivePersonInc%2Fchronosjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LivePersonInc%2Fchronosjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LivePersonInc%2Fchronosjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LivePersonInc","download_url":"https://codeload.github.com/LivePersonInc/chronosjs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248233935,"owners_count":21069493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chronos","commands","communication","courier","events","postmessage","postmessage-api","reqres","request","response"],"created_at":"2024-11-24T11:15:00.135Z","updated_at":"2025-04-10T14:20:32.019Z","avatar_url":"https://github.com/LivePersonInc.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![chronosjs](https://cloud.githubusercontent.com/assets/5138735/8395584/e39bc9cc-1d81-11e5-800e-cd8f5b59025c.png)\n========\n[![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)\n[![Build Status](https://travis-ci.org/LivePersonInc/chronosjs.svg)](https://travis-ci.org/LivePersonInc/chronosjs)\n[![Test Coverage](https://codeclimate.com/github/LivePersonInc/chronosjs/badges/coverage.svg)](https://codeclimate.com/github/LivePersonInc/chronosjs/coverage)\n[![Code Climate](https://codeclimate.com/github/LivePersonInc/chronosjs/badges/gpa.svg)](https://codeclimate.com/github/LivePersonInc/chronosjs)\n[![npm version](https://badge.fury.io/js/chronosjs.svg)](http://badge.fury.io/js/chronosjs)\n[![Dependency Status](https://david-dm.org/LivePersonInc/chronosjs.svg?theme=shields.io)](https://david-dm.org/LivePersonInc/chronosjs)\n[![devDependency Status](https://david-dm.org/LivePersonInc/chronosjs/dev-status.svg?theme=shields.io)](https://david-dm.org/LivePersonInc/chronosjs#info=devDependencies)\n[![npm downloads](https://img.shields.io/npm/dm/chronosjs.svg)](https://img.shields.io/npm/dm/chronosjs.svg)\n[![NPM](https://nodei.co/npm/chronosjs.png)](https://nodei.co/npm/chronosjs/)\n\n\u003e LivePerson's Generic JS Channels Mechanism (Events/Commands/ReqRes)\n\nGetting Started\n---------------\nRun ```npm install chronosjs```\n\nOverview\n-------------\n\nThis library provides an ability to develop event driven applications using the included sub-modules of events, commands and request/response.\n\nTogether with Courier, one can integrate multiple applications into one, by allowing cross domain cross application event driven communication.\n\nAn application developer can integrate/embed a 3rd party application (provided the application uses courier as well) seamlessly and securely without worrying about cross domain issues.\n\nAnother use case is for building multi module application where each module can be it's own application and a developer will want to mix and match between them.\n\n\n### [Chronos.Events](README/Events.md)\nAn events channel for binding and triggering events.\nAllows multiple listeners on a single event and wildcards (`\"*\"`) support.\n\n### [Chronos.Command](README/Commands.md)\nA command mechanism for complying and commanding and API call.\nAllows a single complier per command.\nSupports async commands with an options to call a callback when done.\n\n### [Chronos.ReqRes](README/ReqRes.md)\nA request mechanism for replying and requesting and API call that returns a response.\nAllows a single replier per request.\nSupports async requests with an options to call a callback when done with a result.\n\n### [Chronos.Channels](README/Channels.md)\nA Channel which includes all communication means ([events](README/Events.md), [commands](README/Commands.md), [reqres](README/ReqRes.md)).\nImplements the same API's as all means it contains\n\n### [Chronos.PostMessageCourier](README/Courier.md)\nA generic implementation of Channels over [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).\nAllows communication between cross domain IFRAMES \"sharing\" a [Channels](README/Channels.md) instance.\n\n### Package Contents\nThe package holds a few artifacts in the \u003cb\u003edist\u003c/b\u003e folder:\n- [Events.js](README/Events.md): The events channel\n- [Commands.js](README/Commands.md): The commands channel\n- [Reqres.js](README/ReqRes.md): The request/response channel\n- [Channels.js](README/Channels.md): Combination of all 3 channel options\n- [PostMessageCourierNoDep.js](README/Courier.md): Channel transport over postmessage\n- [PostMessageCourier.js](README/Courier.md): Combination of all 3 channel options with channel transport over postmessage\n\n\u003cb\u003e* Minified compressed versions exist in the *min* folder.\u003c/b\u003e\n\nUsage examples\n---------------\n\n### [Events](README/Events.md)\n```javascript\nvar events = new Chronos.Events();\n\n//Listen on the event only once\nevents.once({\n    appName: \"Your App Name\",\n    eventName: \"Your Event Name\",\n    func: _yourCallBackFunction\n});\n\n//Regular bind on the event\nevents.bind({\n    appName: \"Your App Name\",\n    eventName: \"Your Event Name\",\n    func: _yourCallBackFunction\n});\n\n//Unbind from the event\nevents.unbind({\n    appName: \"Your App Name\",\n    eventName: \"Your Event Name\",\n    func: _yourCallBackFunction\n});\n\n//Trigger the event\nevents.trigger({\n    appName: \"Your App Name\",\n    eventName: \"Your Event Name\",\n    data: {}\n});\n\n//Will return an array of fired events\nevents.hasFired(\"Your App Name\", \"Your Event Name\");\n```\n\nThere is an option to pass `\"*\"` as event name and `\"*\"` as app name on all APIs which is an ALL indicator.\n\n### [Commands](README/Commands.md)\n```javascript\nvar commands = new Chronos.Commands();\n\nfunction _yourCommandExecution(data, cb) {\n    //Do something async with data and call cb when done.\n}\n\n//Comply to a command\ncommands.comply({\n    appName: \"Your App Name\",\n    cmdName: \"Your Command Name\",\n    func: _yourCommandExecution\n});\n\n//Stop complying to a command\ncommands.stopComplying({\n    appName: \"Your App Name\",\n    cmdName: \"Your Command Name\",\n    func: _yourCommandExecution\n});\n\nvar cmd = {\n    appName: \"Your App Name\",\n    cmdName: \"Your Event Name\",\n    data: {}\n}\nfunction notifyWhenDone(err) {\n    if (!err) {\n        console.log('Done executing command');\n    }\n}\n//Issue the command\ncommands.command(cmd, notifyWhenDone);\n\n//Will return an array of fired commands\ncommands.hasFired(\"Your App Name\", \"Your Command Name\");\n```\n\nThe callback on the command is optional.\n\n### [ReqRes](README/ReqRes.md)\n```javascript\nvar reqres = new Chronos.ReqRes();\n\nfunction _yourRequestExecution(data, cb) {\n    //Do something async with data and call cb when done.\n    return 1; //Whatever you want to return\n}\n\n//Reply to a request\nreqres.reply({\n    appName: \"Your App Name\",\n    reqName: \"Your Request Name\",\n    func: _yourRequestExecution\n});\n\n//Stop replying to a request\nreqres.stopReplying({\n    appName: \"Your App Name\",\n    reqName: \"Your Command Name\",\n    func: _yourRequestExecution\n});\n\nvar req = {\n    appName: \"Your App Name\",\n    reqName: \"Your Request Name\",\n    data: {}\n}\nfunction notifyWhenDoneWithResult(err, res) {\n    if (!err) {\n        console.log('Done executing request with result=' + JSON.stringify(res));\n    }\n}\n//Issue the request\nvar res = reqres.command(req, notifyWhenDoneWithResult);\n\n//Will return an array of fired requests\nreqres.hasFired(\"Your App Name\", \"Your Request Name\");\n```\n\nThe callback on the request is optional.\n\n### [PostMessageCourier](README/Courier.md)\n```javascript\n// Initialize a new Courier\nvar courier = Chronos.PostMessageCourier({\n    target: {\n        url: \"http://www.crossdomain.com/\"\n    }\n});\n\n///// ---- BINDINGS ------ ////\ncourier.bind({\n    appName: \"host\",\n    eventName: \"multiply\",\n    func: multiply\n});\ncourier.comply({\n    appName: \"host\",\n    cmdName: \"square\",\n    func: square\n});\ncourier.reply({\n    appName: \"host\",\n    reqName: \"divide\",\n    func: divide\n});\n\n///// ---- INVOCATION ------ ////\ncourier.trigger({\n    appName: \"frame\",\n    eventName: \"got_it\",\n    data: data * 2\n});\ncourier.command({\n    appName: \"frame\",\n    cmdName: \"expect\",\n    data: data\n}, function(err) {\n    if (err) {\n        console.log(\"Problem invoking command\");\n    }\n});\ncourier.request({\n    appName: \"frame\",\n    reqName: \"askBack\",\n    data: data\n}, function(err, data) {\n    if (err) {\n        console.log(\"Problem invoking request\");\n\t    return;\n\t}\n\t// Do Something with the data\n\tconsole.log(data);\n});\n```\n###LIMITATIONS\n- Only supports browsers which implements [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) and have native [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) implementation (IE8+, Chrome, FF, Safari, Opera, IOS, Opera Mini, Android)\n- IE9-, FF \u0026 Opera Mini does not support [MessageChannel](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel) and therefore we fallback to using basic postMessage. This makes the communication opened to any handler registered for messages on the same origin.\n- All passDataByRef flags (in Channels) are obviously ignored\n- In case the browser does not support passing object using postMessage (IE8+, Opera Mini), and no special serialize/deserialize methods are supplied to PostMessageCourier, All data is serialized using JSON.stringify/JSON.parse which means that Object data is limited to JSON which supports types like: strings, numbers, null, arrays, and objects (and does not allow circular references). Trying to serialize other types, will result in conversion to null (like Infinity or NaN) or to a string (Dates), that must be manually deserialized on the other side\n- When the IFRAME is managed outside of [PostMessageCourier](READMDE/Courier.md) (passed by reference to the constructor), a \u003cb\u003etargetOrigin\u003c/b\u003e option is expected to be passed to the constructor, and a query parameter with the name \"lpHost\" is expected on the IFRAME url (unless the [PostMessageCourier](READMDE/Courier.md) at the IFRAME side, had also been initialized with a valid \u003cb\u003etargetOrigin\u003c/b\u003e option)\n\nWrappers\n-----------\n- [ngChronos](/wrappers/angular.md) for angular js.\n\nLicense\n---------\nMIT\n\nCredits\n-------\nThanks to [Danielle Dimenshtein](http://cargocollective.com/danielledim) for the logo\n\nSession on this subject with code examples can be found [here](http://webyoda.github.io/choose-your-channels/#/).\n\n[Demo using Angular and Chronos](http://webyoda.github.io/choose-your-channels/demo/platform/app/index.html#/earth).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivepersoninc%2Fchronosjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flivepersoninc%2Fchronosjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivepersoninc%2Fchronosjs/lists"}