UNPKG

11.2 kBSource Map (JSON)View Raw
1{"version":3,"file":"eventsource.min.js","sources":["../src/web/plugin/eventsource.js","../src/lib/plugin/eventsource.js"],"sourcesContent":["\nimport eventsource from \"../../lib/plugin/eventsource.js\"\n\neventsource(window._hyperscript)\n\n","///=========================================================================\n/// This module provides the EventSource (SSE) feature for hyperscript\n///=========================================================================\n\n/**\n * @param {HyperscriptObject} _hyperscript\n */\nexport default _hyperscript => {\n\t_hyperscript.addFeature(\"eventsource\", function (parser, runtime, tokens) {\n\t\tif (tokens.matchToken(\"eventsource\")) {\n\t\t\tvar urlElement;\n\t\t\tvar withCredentials = false;\n\n\t\t\t// Get the name we'll assign to this EventSource in the hyperscript context\n\t\t\t/** @type {string} */\n\t\t\tvar name = parser.requireElement(\"dotOrColonPath\", tokens).evaluate();\n\t\t\tvar nameSpace = name.split(\".\");\n\t\t\tvar eventSourceName = nameSpace.pop();\n\n\t\t\t// Get the URL of the EventSource\n\t\t\tif (tokens.matchToken(\"from\")) {\n\t\t\t\turlElement = parser.requireElement(\"stringLike\", tokens);\n\t\t\t}\n\n\t\t\t// Get option to connect with/without credentials\n\t\t\tif (tokens.matchToken(\"with\")) {\n\t\t\t\tif (tokens.matchToken(\"credentials\")) {\n\t\t\t\t\twithCredentials = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/** @type {EventSourceStub} */\n\t\t\tvar stub = {\n\t\t\t\teventSource: null,\n\t\t\t\tlisteners: [],\n\t\t\t\tretryCount: 0,\n\t\t\t\topen: function (url) {\n\t\t\t\t\t// calculate default values for URL argument.\n\t\t\t\t\tif (url == undefined) {\n\t\t\t\t\t\tif (stub.eventSource != null && stub.eventSource.url != undefined) {\n\t\t\t\t\t\t\turl = stub.eventSource.url;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow \"no url defined for EventSource.\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Guard multiple opens on the same EventSource\n\t\t\t\t\tif (stub.eventSource != null) {\n\t\t\t\t\t\t// If we're opening a new URL, then close the old one first.\n\t\t\t\t\t\tif (url != stub.eventSource.url) {\n\t\t\t\t\t\t\tstub.eventSource.close();\n\t\t\t\t\t\t} else if (stub.eventSource.readyState != EventSource.CLOSED) {\n\t\t\t\t\t\t\t// Otherwise, we already have the right connection open, so there's nothing left to do.\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Open the EventSource and get ready to populate event handlers\n\t\t\t\t\tstub.eventSource = new EventSource(url, {\n\t\t\t\t\t\twithCredentials: withCredentials,\n\t\t\t\t\t});\n\n\t\t\t\t\t// On successful connection. Reset retry count.\n\t\t\t\t\tstub.eventSource.addEventListener(\"open\", function (event) {\n\t\t\t\t\t\tstub.retryCount = 0;\n\t\t\t\t\t});\n\n\t\t\t\t\t// On connection error, use exponential backoff to retry (random values from 1 second to 2^7 (128) seconds\n\t\t\t\t\tstub.eventSource.addEventListener(\"error\", function (event) {\n\t\t\t\t\t\t// If the EventSource is closed, then try to reopen\n\t\t\t\t\t\tif (stub.eventSource.readyState == EventSource.CLOSED) {\n\t\t\t\t\t\t\tstub.retryCount = Math.min(7, stub.retryCount + 1);\n\t\t\t\t\t\t\tvar timeout = Math.random() * (2 ^ stub.retryCount) * 500;\n\t\t\t\t\t\t\twindow.setTimeout(stub.open, timeout);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Add event listeners\n\t\t\t\t\tfor (var index = 0; index < stub.listeners.length; index++) {\n\t\t\t\t\t\tvar item = stub.listeners[index];\n\t\t\t\t\t\tstub.eventSource.addEventListener(item.type, item.handler, item.options);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tclose: function () {\n\t\t\t\t\tif (stub.eventSource != undefined) {\n\t\t\t\t\t\tstub.eventSource.close();\n\t\t\t\t\t}\n\t\t\t\t\tstub.retryCount = 0;\n\t\t\t\t},\n\t\t\t\taddEventListener: function (type, handler, options) {\n\t\t\t\t\tstub.listeners.push({\n\t\t\t\t\t\ttype: type,\n\t\t\t\t\t\thandler: handler,\n\t\t\t\t\t\toptions: options,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (stub.eventSource != null) {\n\t\t\t\t\t\tstub.eventSource.addEventListener(type, handler, options);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// Create the \"feature\" that will be returned by this function.\n\n\t\t\t/** @type {EventSourceFeature} */\n\t\t\tvar feature = {\n\t\t\t\tname: eventSourceName,\n\t\t\t\tobject: stub,\n\t\t\t\tinstall: function (target) {\n\t\t\t\t\truntime.assignToNamespace(target, nameSpace, eventSourceName, stub);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// Parse each event listener and add it into the list\n\t\t\twhile (tokens.matchToken(\"on\")) {\n\t\t\t\t// get event name\n\t\t\t\tvar eventName = parser.requireElement(\"stringLike\", tokens, \"Expected event name\").evaluate(); // OK to evaluate this in real-time?\n\n\t\t\t\t// default encoding is \"\" (autodetect)\n\t\t\t\tvar encoding = \"\";\n\n\t\t\t\t// look for alternate encoding\n\t\t\t\tif (tokens.matchToken(\"as\")) {\n\t\t\t\t\tencoding = parser.requireElement(\"stringLike\", tokens, \"Expected encoding type\").evaluate(); // Ok to evaluate this in real time?\n\t\t\t\t}\n\n\t\t\t\t// get command list for this event handler\n\t\t\t\tvar commandList = parser.requireElement(\"commandList\", tokens);\n\t\t\t\taddImplicitReturnToCommandList(commandList);\n\t\t\t\ttokens.requireToken(\"end\");\n\n\t\t\t\t// Save the event listener into the feature. This lets us\n\t\t\t\t// connect listeners to new EventSources if we have to reconnect.\n\t\t\t\tstub.listeners.push({\n\t\t\t\t\ttype: eventName,\n\t\t\t\t\thandler: makeHandler(encoding, commandList),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttokens.requireToken(\"end\");\n\n\t\t\t// If we have a URL element, then connect to the remote server now.\n\t\t\t// Otherwise, we can connect later with a call to .open()\n\t\t\tif (urlElement != undefined) {\n\t\t\t\tstub.open(urlElement.evaluate());\n\t\t\t}\n\n\t\t\t// Success!\n\t\t\treturn feature;\n\n\t\t\t////////////////////////////////////////////\n\t\t\t// ADDITIONAL HELPER FUNCTIONS HERE...\n\t\t\t////////////////////////////////////////////\n\n\t\t\t/**\n\t\t\t * Makes an eventHandler function that can execute the correct hyperscript commands\n\t\t\t * This is outside of the main loop so that closures don't cause us to run the wrong commands.\n\t\t\t *\n\t\t\t * @param {string} encoding\n\t\t\t * @param {*} commandList\n\t\t\t * @returns {EventHandlerNonNull}\n\t\t\t */\n\t\t\tfunction makeHandler(encoding, commandList) {\n\t\t\t\treturn function (evt) {\n\t\t\t\t\tvar data = decode(evt[\"data\"], encoding);\n\t\t\t\t\tvar context = runtime.makeContext(stub, feature, stub);\n\t\t\t\t\tcontext.event = evt;\n\t\t\t\t\tcontext.result = data;\n\t\t\t\t\tcommandList.execute(context);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Decodes/Unmarshals a string based on the selected encoding. If the\n\t\t\t * encoding is not recognized, attempts to auto-detect based on its content\n\t\t\t *\n\t\t\t * @param {string} data - The original data to be decoded\n\t\t\t * @param {string} encoding - The method that the data is currently encoded (\"string\", \"json\", or unknown)\n\t\t\t * @returns {string} - The decoded data\n\t\t\t */\n\t\t\tfunction decode(data, encoding) {\n\t\t\t\t// Force JSON encoding\n\t\t\t\tif (encoding == \"json\") {\n\t\t\t\t\treturn JSON.parse(data);\n\t\t\t\t}\n\n\t\t\t\t// Otherwise, return the data without modification\n\t\t\t\treturn data;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Adds a \"HALT\" command to the commandList.\n\t\t\t * TODO: This seems like something that could be optimized:\n\t\t\t * maybe the parser could do automatically,\n\t\t\t * or could be a public function in the parser available to everyone,\n\t\t\t * or the command-executer-thingy could just handle nulls implicitly.\n\t\t\t *\n\t\t\t * @param {*} commandList\n\t\t\t * @returns void\n\t\t\t */\n\t\t\tfunction addImplicitReturnToCommandList(commandList) {\n\t\t\t\tif (commandList.next) {\n\t\t\t\t\treturn addImplicitReturnToCommandList(commandList.next);\n\t\t\t\t}\n\n\t\t\t\tcommandList.next = {\n\t\t\t\t\ttype: \"implicitReturn\",\n\t\t\t\t\top: function (/** @type {Context} */ _context) {\n\t\t\t\t\t\treturn runtime.HALT;\n\t\t\t\t\t},\n\t\t\t\t\texecute: function (/** @type {Context} */ _context) {\n\t\t\t\t\t\t// do nothing\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t});\n}"],"names":["window","_hyperscript","addFeature","parser","runtime","tokens","matchToken","urlElement","makeHandler","encoding","commandList","evt","data","decode","context","makeContext","stub","feature","event","result","execute","JSON","parse","addImplicitReturnToCommandList","next","type","op","_context","HALT","withCredentials","nameSpace","requireElement","evaluate","split","eventSourceName","pop","eventSource","listeners","retryCount","open","url","undefined","close","readyState","EventSource","CLOSED","addEventListener","Math","min","timeout","random","setTimeout","index","length","item","handler","options","push","name","object","install","target","assignToNamespace","eventName","requireToken"],"mappings":"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"}
\No newline at end of file