{"_id":"@ayonli/sse","_rev":"2-f391395efd6df27c97530ea3449e3433","name":"@ayonli/sse","dist-tags":{"latest":"0.4.1"},"versions":{"0.4.0":{"name":"@ayonli/sse","version":"0.4.0","keywords":["see"],"author":{"name":"A-yon Lee","email":"the@ayon.li"},"license":"MIT","_id":"@ayonli/sse@0.4.0","maintainers":[{"name":"ayonli","email":"the@ayon.li"}],"homepage":"https://github.com/ayonli/sse#readme","bugs":{"url":"https://github.com/ayonli/sse/issues"},"dist":{"shasum":"e9675b9e161462328ba8befceeb961131324b256","tarball":"https://registry.npmjs.org/@ayonli/sse/-/sse-0.4.0.tgz","fileCount":6,"integrity":"sha512-ruGYmCNT3SrJoinEKbFHjwE0jUgOkSw5FSoVJUJ68ewPG55an2x1xI26KsZ+MhCsxhcpbB/CTZKw68bnrCjvRw==","signatures":[{"sig":"MEQCIC8wZXpybEWNnOqPw47WM78forkRZAFVv5IvgwIEmr9sAiAVFzvVTDKh40jxgvLmjUkFU6l5vaR+ZDSkO0n7k83jhQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":16274},"main":"index.js","types":"index.d.ts","engines":{"node":">=6"},"gitHead":"6de3ae31fa4960f7b8ae8bee08a6fda4f34ad101","scripts":{"test":"mocha","pretest":"tsc --module commonjs --target es2015 test.ts","posttest":"rm -f test.js* && rm -f index.js*","postpublish":"ls index.* | grep -v index.ts | xargs rm -f","prepublishOnly":"tsc --module commonjs --target es2015 --declaration true --sourcemap true --noImplicitThis true index.ts"},"_npmUser":{"name":"ayonli","email":"the@ayon.li"},"repository":{"url":"git+https://github.com/ayonli/sse.git","type":"git"},"_npmVersion":"9.5.0","description":"Server-Sent Events implementation for Node.js with Session Support Enhancement.","directories":{},"_nodeVersion":"18.14.2","dependencies":{"nanoid":"^3.1.20"},"_hasShrinkwrap":false,"devDependencies":{"mocha":"^6.1.4","typescript":"^4.9.5","@types/node":"^14.14.31","eventsource":"^1.1.2","@types/mocha":"^5.2.7"},"_npmOperationalInternal":{"tmp":"tmp/sse_0.4.0_1693100363324_0.42240793564904444","host":"s3://npm-registry-packages"},"deprecated":"Use @ayonli/jsext/sse instead"},"0.4.1":{"name":"@ayonli/sse","version":"0.4.1","keywords":["see"],"author":{"name":"A-yon Lee","email":"the@ayon.li"},"license":"MIT","_id":"@ayonli/sse@0.4.1","maintainers":[{"name":"ayonli","email":"the@ayon.li"}],"homepage":"https://github.com/ayonli/sse#readme","bugs":{"url":"https://github.com/ayonli/sse/issues"},"dist":{"shasum":"12959c42cd2a14ce837ca1ed937e08c39d6dd770","tarball":"https://registry.npmjs.org/@ayonli/sse/-/sse-0.4.1.tgz","fileCount":8,"integrity":"sha512-U+P/h7LjVUYmsMvYUHKM9DsmF28JfVGT7Xq32lyLgxnKW8PpElEQFKuxtDXeoPPEwg3EGSfyPM5Wa25TDwUlWQ==","signatures":[{"sig":"MEQCIChrEOKqkU4QhPJD1R92JtslqMpXe5u+SVvq25u2EhabAiAFCt2GaHmTy0Kod8gm8otd6dahDJVz5Gr1vw2j13Uakw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":28459},"main":"index.js","engines":{"node":">=6"},"gitHead":"8767e120c22ee2dda05e1c5f827b3bffe7063627","scripts":{"test":"mocha test.js","build":"tsc --module commonjs --target es2015 --sourcemap --strict *.ts","pretest":"npm run build","posttest":"npm run postpublish","test:bun":"bun run ./node_modules/mocha/bin/mocha test.ts","postpublish":"ls *.js | xargs rm; ls *.js.map | xargs rm","prepublishOnly":"npm run build"},"_npmUser":{"name":"ayonli","email":"the@ayon.li"},"repository":{"url":"git+https://github.com/ayonli/sse.git","type":"git"},"_npmVersion":"9.5.0","description":"Server-Sent Events implementation for Node.js with Session Support Enhancement.","directories":{},"_nodeVersion":"18.14.2","dependencies":{"nanoid":"^3.1.20"},"_hasShrinkwrap":false,"devDependencies":{"mocha":"^6.1.4","typescript":"^4.9.5","@types/node":"^20.6.2","eventsource":"^1.1.2","@types/mocha":"^5.2.7","@ayonli/jsext":"^0.4.5"},"_npmOperationalInternal":{"tmp":"tmp/sse_0.4.1_1695041525390_0.40864280953404575","host":"s3://npm-registry-packages"},"deprecated":"Use @ayonli/jsext/sse instead"}},"time":{"created":"2023-08-27T01:39:23.249Z","modified":"2024-08-03T06:09:13.021Z","0.4.0":"2023-08-27T01:39:23.546Z","0.4.1":"2023-09-18T12:52:05.584Z"},"bugs":{"url":"https://github.com/ayonli/sse/issues"},"author":{"name":"A-yon Lee","email":"the@ayon.li"},"license":"MIT","homepage":"https://github.com/ayonli/sse#readme","keywords":["see"],"repository":{"url":"git+https://github.com/ayonli/sse.git","type":"git"},"description":"Server-Sent Events implementation for Node.js with Session Support Enhancement.","maintainers":[{"name":"ayonli","email":"the@ayon.li"}],"readme":"# SSE\n\n[Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html)\nimplementation for Node.js with Session Support Enhancement.\n\n## Install\n\n```sh\nnpm install @ayonli/sse\n```\n\n## Example\n\n```ts\nimport * as http from \"http\";\nimport { SSE } from \"@ayonli/sse\";\n\nconst store = new Map<string, SSE>();\n\n// Sync server time to the clients every minute.\nsetTimeout(() => {\n    const time = new Date().toISOString();\n\n    store.forEach((sse) => {\n        sse.emit(\"sync-time\", time);\n    })\n}, 60_000);\n\nconst server = http.createServer((req, res) => {\n    if (SSE.isEventSource(req)) {\n        const sse = new SSE(req, res);\n\n        if (sse.isClosed) { // Check if the the connection has been marked closed.\n            return;\n        } else {\n            store.set(sse.id, sse); // Store the SSE instance for future use.\n\n            sse.emit(\"connect\"); // notify connection established.\n\n            res.once(\"close\", () => {\n                // Remove the SSE instance once the connection is lost.\n                store.delete(sse.id);\n            });\n        }\n    } else {\n        // do other stuffs\n    }\n});\n\nserver.listen(80);\n```\n\n**Client Side:**\n\n```javascript\nconst es = new EventSource(\"http://localhost\");\n\n// Listen to server-sent event for data.\nes.addEventListener(\"sync-time\", event => {\n    console.log(\"server time:\", event.data);\n});\n```\n\n## API\n\n- `new SSE(req, res, retry?: number)`\n    - `retry` The re-connection time to use when attempting to send the event.\n- `sse.id: string` The unique ID of the SSE connection, also used as \n    `lastEventId` of the client EventSource, when the client reconnect, this ID \n    will be reused.\n- `sse.isNew: boolean` Whether the connection is newly created.\n- `sse.isClosed: boolean` Whether the connection is closed. This property is \n    used to check whether a re-connection has been marked closed, once closed, \n    the server must not do anything continuing.\n- `writeHead(code: number, headers?: { [x: string]: string | string[] }): this`\n    Sends a response header to the client.\n- `send(data: any): boolean` Sends data to the client which will be received by\n    the `es.onmessage` callback function. Data will be serialize via JSON if\n    they're not string.\n- `emit(event: string, data?: any): boolean` Emits an event to the client, the \n    message will be dispatched on the browser to the listener for the specified \n    event name; the website source code should use `es.addEventListener()` to \n    listen for named events.\n- `close(cb?: () => void): void` Closes the connection.\n\n## About `sse.id`\n\n`sse.id` (AKA `lastEventId`) is generated by the server for each connection and\nreused during reconnection, in real world, it can be used as a session ID of the\nbrowser tab, meaning the server can identify each tab according to this ID, this\nis useful when the server wish to send data to a specific browser tab.\n\nNormally, this ID is generated by the server automatically, but the client can\nprovide it during the initial connection, this is useful when the client wish\nto reused a historical ID stored locally. For example, we can store the\nprevious ID in the `sessionStorage,` and reuse it after the browser tab has been\nrefreshed, which guarantees each tab is memorable to the server (trust me, this\nis very useful).\n\nThis is how:\n\n```ts\nconst sseId = sessionStorage.getItem(\"sseId\");\nconst es = new EventSource(\"http://localhost\" + sseId ? `?id=${sseId}` : \"\");\n\nes.addEventListener(\"connect\", event => {\n    sessionStorage.setItem(\"sseId\", event.lastEventId);\n});\n```\n\nNOTE: don't store the ID in `localStorage`, which is shared across all tabs of\nthe same site.\n\n## About Closing\n\nAccording to the\n[Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html) \nprotocol, the server cannot entirely close the connection without re-connection \nfiring on the client, unless the server send a `204` status code telling the \nclient not to, so this package provided an approach to handle this procedure \ninternally.\n\nOnce `sse.close()` method is called, the server will close the current  HTTP\nconnection, and mark the `id` closed, so that when the client try to reconnect,\nthe server can identify it as a closed connection and send `204`  automatically\nand immediately to prevent the client re-connecting.\n\nThat said, the server should check the property `isClosed` at the very beginning\nof the request life cycle, to see if a connection has been marked closed, once\nclosed, the server must not do anything continuing.\n\nApart from closing the connection on the server side, the client can call\n`es.close()` to close the connection positively, and no-reconnection will be\nfired afterwards.\n","readmeFilename":"README.md"}