datastar-ssegen 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +24 -0
 - package/README.md +89 -0
 - package/examples/commonHandlers.js +91 -0
 - package/examples/express.example.js +38 -0
 - package/examples/hyper-express.example.js +42 -0
 - package/examples/node.example.js +71 -0
 - package/index.js +273 -0
 - package/package.json +31 -0
 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # publish to npm
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: Publish Package
         
     | 
| 
      
 3 
     | 
    
         
            +
            on:
         
     | 
| 
      
 4 
     | 
    
         
            +
              push:
         
     | 
| 
      
 5 
     | 
    
         
            +
                branches:
         
     | 
| 
      
 6 
     | 
    
         
            +
                  - main
         
     | 
| 
      
 7 
     | 
    
         
            +
              release:
         
     | 
| 
      
 8 
     | 
    
         
            +
                types:
         
     | 
| 
      
 9 
     | 
    
         
            +
                  - created
         
     | 
| 
      
 10 
     | 
    
         
            +
            jobs:
         
     | 
| 
      
 11 
     | 
    
         
            +
              publish:
         
     | 
| 
      
 12 
     | 
    
         
            +
                runs-on: ubuntu-latest
         
     | 
| 
      
 13 
     | 
    
         
            +
                steps:
         
     | 
| 
      
 14 
     | 
    
         
            +
                  - name: Checkout code
         
     | 
| 
      
 15 
     | 
    
         
            +
                    uses: actions/checkout@v3
         
     | 
| 
      
 16 
     | 
    
         
            +
                  - name: Setup Node.js environment
         
     | 
| 
      
 17 
     | 
    
         
            +
                    uses: actions/setup-node@v3
         
     | 
| 
      
 18 
     | 
    
         
            +
                    with:
         
     | 
| 
      
 19 
     | 
    
         
            +
                      node-version: '18'
         
     | 
| 
      
 20 
     | 
    
         
            +
                      registry-url: 'https://registry.npmjs.org/'
         
     | 
| 
      
 21 
     | 
    
         
            +
                  - name: Publish to npm
         
     | 
| 
      
 22 
     | 
    
         
            +
                    run: npm publish
         
     | 
| 
      
 23 
     | 
    
         
            +
                    env:
         
     | 
| 
      
 24 
     | 
    
         
            +
                      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
         
     | 
    
        package/README.md
    ADDED
    
    | 
         @@ -0,0 +1,89 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            
         
     | 
| 
      
 2 
     | 
    
         
            +
            
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            # datastar-ssegen
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## Overview
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            The `datastar-ssegen` is a backend JavaScript module designed to generate Server-Sent Events (SSE) for connected [Datastar](https://data-star.dev/) clients. It supports popular server frameworks such as Express.js, Node.js, and Hyper Express.js.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            This package is engineered to integrate tightly with request and response objects of these backend frameworks, enabling efficient and reactive web application development.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            ### Key Features
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            - Real-time updates with Server-Sent Events tailored for Datastar clients
         
     | 
| 
      
 15 
     | 
    
         
            +
            - Seamless integration with Express.js, Hyper Express.js, and Node HTTP
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            ### Installation
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            Install the package via npm:
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 22 
     | 
    
         
            +
            npm install datastar-ssegen
         
     | 
| 
      
 23 
     | 
    
         
            +
            ```
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ### Quick Start Example with Express.js
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            Here's a straightforward example of setting up an Express.js server with the datastar-ssegen:
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            ```javascript
         
     | 
| 
      
 30 
     | 
    
         
            +
            import express from 'express';
         
     | 
| 
      
 31 
     | 
    
         
            +
            import { ServerSentEventGenerator } from 'datastar-ssegen';
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            const app = express();
         
     | 
| 
      
 34 
     | 
    
         
            +
            app.use(express.json());
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            // Define event handlers here
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            app.get('/messages', handleMessages);
         
     | 
| 
      
 39 
     | 
    
         
            +
            app.get('/clock', handleClock);
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            const PORT = 3101;
         
     | 
| 
      
 42 
     | 
    
         
            +
            app.listen(PORT, () => {
         
     | 
| 
      
 43 
     | 
    
         
            +
              console.log(`Server running at http://localhost:${PORT}`);
         
     | 
| 
      
 44 
     | 
    
         
            +
            });
         
     | 
| 
      
 45 
     | 
    
         
            +
            ```
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            ### Client Interaction Example
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            Here's a simple HTML page to interact with the server:
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            ```html
         
     | 
| 
      
 52 
     | 
    
         
            +
            <!DOCTYPE html>
         
     | 
| 
      
 53 
     | 
    
         
            +
            <html lang="en">
         
     | 
| 
      
 54 
     | 
    
         
            +
            <head>
         
     | 
| 
      
 55 
     | 
    
         
            +
              <meta charset="UTF-8">
         
     | 
| 
      
 56 
     | 
    
         
            +
              <meta http-equiv="X-UA-Compatible" content="IE=edge">
         
     | 
| 
      
 57 
     | 
    
         
            +
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
         
     | 
| 
      
 58 
     | 
    
         
            +
              <script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar/bundles/datastar.js"></script>
         
     | 
| 
      
 59 
     | 
    
         
            +
              <title>SSE Example</title>
         
     | 
| 
      
 60 
     | 
    
         
            +
            </head>
         
     | 
| 
      
 61 
     | 
    
         
            +
            <body>
         
     | 
| 
      
 62 
     | 
    
         
            +
              <h1>SSE Demo</h1>
         
     | 
| 
      
 63 
     | 
    
         
            +
              <div id="greeting-area">Greeting: <button onclick="sse('/messages')">Get Greeting</button></div>
         
     | 
| 
      
 64 
     | 
    
         
            +
              <div id="clock-area">Current Time: <button onclick="sse('/clock')">Start Clock</button></div>
         
     | 
| 
      
 65 
     | 
    
         
            +
            </body>
         
     | 
| 
      
 66 
     | 
    
         
            +
            </html>
         
     | 
| 
      
 67 
     | 
    
         
            +
            ```
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            ### Available Functions
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            The `ServerSentEventGenerator` provides several functions to facilitate communication with connected Datastar clients using Server-Sent Events:
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            - **`init(request, response)`**: Initializes SSE communication with the specified request and response.
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            - **`_send(eventType, dataLines, sendOptions)`**: Sends a server-sent event (SSE) to the client. Options include setting an `eventId` and defining `retryDuration`.
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            - **`ReadSignals(signals)`**: Reads and merges signals based on HTTP methods with predefined signals, useful for parsing query or body data sent to the server.
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            - **`MergeFragments(fragments, options)`**: Sends a merge fragments event to update HTML content on the client. Options include `selector`, `mergeMode`, `settleDuration`, and `useViewTransition`.
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            - **`RemoveFragments(selector, options)`**: Dispatches events to remove HTML elements based on a CSS selector. Options can set a `settleDuration` or `useViewTransition`.
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            - **`MergeSignals(signals, options)`**: Sends a merge signals event to update or add client-side signals. Options may include `onlyIfMissing`.
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            - **`RemoveSignals(paths, options)`**: Sends an event to remove specific client-side signals identified by paths.
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            - **`ExecuteScript(script, options)`**: Directs the client to execute specified JavaScript code. Options can enable `autoRemove` of the script after execution.
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            This expanded set provides comprehensive functionality to build interactive web applications with real-time updates and dynamic HTML and signal management.
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import { ServerSentEventGenerator } from "../index.js";
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            export let backendStore = {
         
     | 
| 
      
 4 
     | 
    
         
            +
              someBackendValue: "This is something",
         
     | 
| 
      
 5 
     | 
    
         
            +
            };
         
     | 
| 
      
 6 
     | 
    
         
            +
            export const homepage = (name = "") => {
         
     | 
| 
      
 7 
     | 
    
         
            +
              return `<html>
         
     | 
| 
      
 8 
     | 
    
         
            +
              <head>
         
     | 
| 
      
 9 
     | 
    
         
            +
                <title>${name} Datastar Test</title>
         
     | 
| 
      
 10 
     | 
    
         
            +
                <script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@develop/bundles/datastar.js"></script>
         
     | 
| 
      
 11 
     | 
    
         
            +
              </head>
         
     | 
| 
      
 12 
     | 
    
         
            +
              <body>
         
     | 
| 
      
 13 
     | 
    
         
            +
                <h3>${name} Datastar Test</h3>
         
     | 
| 
      
 14 
     | 
    
         
            +
                <div data-signals="{theme: 'light', lastUpdate:'Never', xyz:'some signal'}">
         
     | 
| 
      
 15 
     | 
    
         
            +
                  <h3>Long Lived SSE:</h3>
         
     | 
| 
      
 16 
     | 
    
         
            +
                  <div id="clock" data-on-load="sse('/clock')">...Loading Clock</div>
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  <h3>MergeSignals:</h3>
         
     | 
| 
      
 19 
     | 
    
         
            +
                  <div>Last User Interaction:<span data-text="lastUpdate.value"></span></div>
         
     | 
| 
      
 20 
     | 
    
         
            +
                  <h3>Merge Fragments</h3>
         
     | 
| 
      
 21 
     | 
    
         
            +
                  <div id="quote">No Quote</div>
         
     | 
| 
      
 22 
     | 
    
         
            +
                  <button data-on-click="sse('/quote')">MergeFragments</button>
         
     | 
| 
      
 23 
     | 
    
         
            +
                  <h3>RemoveFragments</h3>
         
     | 
| 
      
 24 
     | 
    
         
            +
                  <div id="trash">
         
     | 
| 
      
 25 
     | 
    
         
            +
                    Remove me please!
         
     | 
| 
      
 26 
     | 
    
         
            +
                    <button data-on-click="sse('/removeTrash')">RemoveFragments</button>
         
     | 
| 
      
 27 
     | 
    
         
            +
                  </div>
         
     | 
| 
      
 28 
     | 
    
         
            +
                  <h3>ExecuteScript</h3>
         
     | 
| 
      
 29 
     | 
    
         
            +
                  <div>Print to Console</div>
         
     | 
| 
      
 30 
     | 
    
         
            +
                  <button data-on-click="sse('/printToConsole')">ExecuteScript</button>
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  <h3>ReadSignals</h3>
         
     | 
| 
      
 33 
     | 
    
         
            +
                  <button data-on-click="sse('/readSignals')">ReadSignals</button>
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  <h3>ReadSignals (post)</h3>
         
     | 
| 
      
 36 
     | 
    
         
            +
                  <button data-on-click="sse('/readSignals', {method: 'post'})">ReadSignals (post)</button>
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  <h3>RemoveSignals</h3>
         
     | 
| 
      
 40 
     | 
    
         
            +
                  <div>Signal xyz:<span data-text="xyz.value"></span></div>
         
     | 
| 
      
 41 
     | 
    
         
            +
                  <button data-on-click="sse('/removeSignal')">Test RemoveSignals: xyz</button>
         
     | 
| 
      
 42 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 43 
     | 
    
         
            +
              </body>
         
     | 
| 
      
 44 
     | 
    
         
            +
              </html>`;
         
     | 
| 
      
 45 
     | 
    
         
            +
            };
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            export const handleQuote = async (req, res) => {
         
     | 
| 
      
 48 
     | 
    
         
            +
              const sse = ServerSentEventGenerator.init(req, res);
         
     | 
| 
      
 49 
     | 
    
         
            +
              const qoutes = [
         
     | 
| 
      
 50 
     | 
    
         
            +
                "Any app that can be written in JavaScript, will eventually be written in JavaScript. - Jeff Atwood",
         
     | 
| 
      
 51 
     | 
    
         
            +
                "JavaScript is the world's most misunderstood programming language. - Douglas Crockford",
         
     | 
| 
      
 52 
     | 
    
         
            +
                "The strength of JavaScript is that you can do anything. The weakness is that you will. - Reg Braithwaite",
         
     | 
| 
      
 53 
     | 
    
         
            +
              ];
         
     | 
| 
      
 54 
     | 
    
         
            +
              const randomQuote = (arr) => arr[Math.floor(Math.random() * arr.length)];
         
     | 
| 
      
 55 
     | 
    
         
            +
              await sse.MergeFragments(`<div id="quote">${randomQuote(qoutes)}</div>`);
         
     | 
| 
      
 56 
     | 
    
         
            +
              await sse.MergeSignals({ lastUpdate: Date.now() });
         
     | 
| 
      
 57 
     | 
    
         
            +
              res.end();
         
     | 
| 
      
 58 
     | 
    
         
            +
            };
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            export const handleReadSignals = async (req, res) => {
         
     | 
| 
      
 61 
     | 
    
         
            +
              const sse = ServerSentEventGenerator.init(req, res);
         
     | 
| 
      
 62 
     | 
    
         
            +
              backendStore = await sse.ReadSignals(backendStore);
         
     | 
| 
      
 63 
     | 
    
         
            +
              console.log("backendStore updated", backendStore);
         
     | 
| 
      
 64 
     | 
    
         
            +
              res.end();
         
     | 
| 
      
 65 
     | 
    
         
            +
            };
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            export const handleRemoveTrash = async (req, res) => {
         
     | 
| 
      
 68 
     | 
    
         
            +
              const sse = ServerSentEventGenerator.init(req, res);
         
     | 
| 
      
 69 
     | 
    
         
            +
              await sse.RemoveFragments("#trash");
         
     | 
| 
      
 70 
     | 
    
         
            +
              await sse.MergeSignals({ lastUpdate: Date.now() });
         
     | 
| 
      
 71 
     | 
    
         
            +
              res.end();
         
     | 
| 
      
 72 
     | 
    
         
            +
            };
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            export const handleExecuteScript = async (req, res) => {
         
     | 
| 
      
 75 
     | 
    
         
            +
              const sse = ServerSentEventGenerator.init(req, res);
         
     | 
| 
      
 76 
     | 
    
         
            +
              await sse.ExecuteScript(`console.log("Hello from the backend!")`);
         
     | 
| 
      
 77 
     | 
    
         
            +
              await sse.MergeSignals({ lastUpdate: Date.now() });
         
     | 
| 
      
 78 
     | 
    
         
            +
              res.end();
         
     | 
| 
      
 79 
     | 
    
         
            +
            };
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            export const handleClock = async function (req, res) {
         
     | 
| 
      
 82 
     | 
    
         
            +
              const sse = ServerSentEventGenerator.init(req, res);
         
     | 
| 
      
 83 
     | 
    
         
            +
              setInterval(async () => {
         
     | 
| 
      
 84 
     | 
    
         
            +
                await sse.MergeFragments(`<div id="clock">${new Date()}</div>`);
         
     | 
| 
      
 85 
     | 
    
         
            +
              }, 1000);
         
     | 
| 
      
 86 
     | 
    
         
            +
            };
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            export const handleRemoveSignal = async (req, res) => {
         
     | 
| 
      
 89 
     | 
    
         
            +
              const sse = ServerSentEventGenerator.init(req, res);
         
     | 
| 
      
 90 
     | 
    
         
            +
              await sse.RemoveSignals(["xyz"]);
         
     | 
| 
      
 91 
     | 
    
         
            +
            };
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import express from "express";
         
     | 
| 
      
 2 
     | 
    
         
            +
            import { ServerSentEventGenerator } from "../index.js";
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            import {
         
     | 
| 
      
 5 
     | 
    
         
            +
              homepage,
         
     | 
| 
      
 6 
     | 
    
         
            +
              handleQuote,
         
     | 
| 
      
 7 
     | 
    
         
            +
              handleReadSignals,
         
     | 
| 
      
 8 
     | 
    
         
            +
              handleRemoveTrash,
         
     | 
| 
      
 9 
     | 
    
         
            +
              handleExecuteScript,
         
     | 
| 
      
 10 
     | 
    
         
            +
              handleClock,
         
     | 
| 
      
 11 
     | 
    
         
            +
              handleRemoveSignal,
         
     | 
| 
      
 12 
     | 
    
         
            +
            } from "./commonHandlers.js";
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            const app = express();
         
     | 
| 
      
 15 
     | 
    
         
            +
            const PORT = 3101;
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            // Middleware to parse incoming JSON bodies if needed
         
     | 
| 
      
 18 
     | 
    
         
            +
            app.use(express.json());
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            app.get("/", (req, res) => {
         
     | 
| 
      
 21 
     | 
    
         
            +
              res.send(homepage("Express.js"));
         
     | 
| 
      
 22 
     | 
    
         
            +
            });
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            app.get("/quote", handleQuote);
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            app.get("/readSignals", handleReadSignals);
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            app.get("/removeTrash", handleRemoveTrash);
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            app.get("/printToConsole", handleExecuteScript);
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            app.get("/clock", handleClock);
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            app.get("/removeSignal", handleRemoveSignal);
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            app.listen(PORT, () => {
         
     | 
| 
      
 37 
     | 
    
         
            +
              console.log(`Express.js server http://localhost:${PORT}`);
         
     | 
| 
      
 38 
     | 
    
         
            +
            });
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import HyperExpress from "hyper-express";
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import {
         
     | 
| 
      
 4 
     | 
    
         
            +
              homepage,
         
     | 
| 
      
 5 
     | 
    
         
            +
              handleQuote,
         
     | 
| 
      
 6 
     | 
    
         
            +
              handleReadSignals,
         
     | 
| 
      
 7 
     | 
    
         
            +
              handleRemoveTrash,
         
     | 
| 
      
 8 
     | 
    
         
            +
              handleExecuteScript,
         
     | 
| 
      
 9 
     | 
    
         
            +
              handleClock,
         
     | 
| 
      
 10 
     | 
    
         
            +
              handleRemoveSignal,
         
     | 
| 
      
 11 
     | 
    
         
            +
            } from "./commonHandlers.js";
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            // Initialize HyperExpress server
         
     | 
| 
      
 14 
     | 
    
         
            +
            const server = new HyperExpress.Server();
         
     | 
| 
      
 15 
     | 
    
         
            +
            const PORT = 3102;
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            // Configure routes
         
     | 
| 
      
 18 
     | 
    
         
            +
            server.get("/", (req, res) => {
         
     | 
| 
      
 19 
     | 
    
         
            +
              res.html(homepage("hyper-express"));
         
     | 
| 
      
 20 
     | 
    
         
            +
            });
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            server.get("/quote", handleQuote);
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            server.get("/readSignals", handleReadSignals);
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            server.get("/removeTrash", handleRemoveTrash);
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            server.get("/printToConsole", handleExecuteScript);
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            server.get("/clock", handleClock);
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            server.get("/removeSignal", handleRemoveSignal);
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            // Start the server
         
     | 
| 
      
 35 
     | 
    
         
            +
            server
         
     | 
| 
      
 36 
     | 
    
         
            +
              .listen(PORT)
         
     | 
| 
      
 37 
     | 
    
         
            +
              .then(() => {
         
     | 
| 
      
 38 
     | 
    
         
            +
                console.log(`HyperExpress server http://localhost:${PORT}`);
         
     | 
| 
      
 39 
     | 
    
         
            +
              })
         
     | 
| 
      
 40 
     | 
    
         
            +
              .catch((error) => {
         
     | 
| 
      
 41 
     | 
    
         
            +
                console.error("Error starting server:", error);
         
     | 
| 
      
 42 
     | 
    
         
            +
              });
         
     | 
| 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import http from "http";
         
     | 
| 
      
 2 
     | 
    
         
            +
            import {
         
     | 
| 
      
 3 
     | 
    
         
            +
              homepage,
         
     | 
| 
      
 4 
     | 
    
         
            +
              handleQuote,
         
     | 
| 
      
 5 
     | 
    
         
            +
              handleReadSignals,
         
     | 
| 
      
 6 
     | 
    
         
            +
              handleRemoveTrash,
         
     | 
| 
      
 7 
     | 
    
         
            +
              handleExecuteScript,
         
     | 
| 
      
 8 
     | 
    
         
            +
              handleClock,
         
     | 
| 
      
 9 
     | 
    
         
            +
              handleRemoveSignal,
         
     | 
| 
      
 10 
     | 
    
         
            +
            } from "./commonHandlers.js";
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            import url from "url";
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            // Initialize an HTTP server
         
     | 
| 
      
 15 
     | 
    
         
            +
            const PORT = 3100;
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            const server = http.createServer((req, res) => {
         
     | 
| 
      
 18 
     | 
    
         
            +
              if (req.method === "GET") {
         
     | 
| 
      
 19 
     | 
    
         
            +
                const parsedUrl = url.parse(req.url);
         
     | 
| 
      
 20 
     | 
    
         
            +
                switch (parsedUrl.pathname) {
         
     | 
| 
      
 21 
     | 
    
         
            +
                  case "/":
         
     | 
| 
      
 22 
     | 
    
         
            +
                    res.writeHead(200, { "Content-Type": "text/html" });
         
     | 
| 
      
 23 
     | 
    
         
            +
                    res.end(homepage("node.js"));
         
     | 
| 
      
 24 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  case "/quote":
         
     | 
| 
      
 27 
     | 
    
         
            +
                    handleQuote(req, res);
         
     | 
| 
      
 28 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  case "/readSignals":
         
     | 
| 
      
 31 
     | 
    
         
            +
                    handleReadSignals(req, res);
         
     | 
| 
      
 32 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  case "/removeTrash":
         
     | 
| 
      
 35 
     | 
    
         
            +
                    handleRemoveTrash(req, res);
         
     | 
| 
      
 36 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  case "/printToConsole":
         
     | 
| 
      
 39 
     | 
    
         
            +
                    handleExecuteScript(req, res);
         
     | 
| 
      
 40 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  case "/clock":
         
     | 
| 
      
 43 
     | 
    
         
            +
                    handleClock(req, res);
         
     | 
| 
      
 44 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  case "/removeSignal":
         
     | 
| 
      
 47 
     | 
    
         
            +
                    handleRemoveSignal(req, res);
         
     | 
| 
      
 48 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  default:
         
     | 
| 
      
 51 
     | 
    
         
            +
                    res.writeHead(404, { "Content-Type": "text/plain" });
         
     | 
| 
      
 52 
     | 
    
         
            +
                    res.end("404 Not Found");
         
     | 
| 
      
 53 
     | 
    
         
            +
                }
         
     | 
| 
      
 54 
     | 
    
         
            +
              } else if (req.method === "POST") {
         
     | 
| 
      
 55 
     | 
    
         
            +
                const parsedUrl = url.parse(req.url);
         
     | 
| 
      
 56 
     | 
    
         
            +
                switch (parsedUrl.pathname) {
         
     | 
| 
      
 57 
     | 
    
         
            +
                  case "/readSignals":
         
     | 
| 
      
 58 
     | 
    
         
            +
                    console.log("post readsignals");
         
     | 
| 
      
 59 
     | 
    
         
            +
                    handleReadSignals(req, res);
         
     | 
| 
      
 60 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 61 
     | 
    
         
            +
                }
         
     | 
| 
      
 62 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 63 
     | 
    
         
            +
                res.writeHead(405, { "Content-Type": "text/plain" });
         
     | 
| 
      
 64 
     | 
    
         
            +
                res.end("Method Not Allowed");
         
     | 
| 
      
 65 
     | 
    
         
            +
              }
         
     | 
| 
      
 66 
     | 
    
         
            +
            });
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            // Start the server
         
     | 
| 
      
 69 
     | 
    
         
            +
            server.listen(PORT, () => {
         
     | 
| 
      
 70 
     | 
    
         
            +
              console.log(`Node.js server http://localhost:${PORT}`);
         
     | 
| 
      
 71 
     | 
    
         
            +
            });
         
     | 
    
        package/index.js
    ADDED
    
    | 
         @@ -0,0 +1,273 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import url from "url";
         
     | 
| 
      
 2 
     | 
    
         
            +
            import querystring from "querystring";
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            /**
         
     | 
| 
      
 5 
     | 
    
         
            +
             * ServerSentEventGenerator is responsible for initializing and handling
         
     | 
| 
      
 6 
     | 
    
         
            +
             * server-sent events (SSE) for different web frameworks.
         
     | 
| 
      
 7 
     | 
    
         
            +
             */
         
     | 
| 
      
 8 
     | 
    
         
            +
            export const ServerSentEventGenerator = {
         
     | 
| 
      
 9 
     | 
    
         
            +
              /**
         
     | 
| 
      
 10 
     | 
    
         
            +
               * Initializes the server-sent event generator.
         
     | 
| 
      
 11 
     | 
    
         
            +
               *
         
     | 
| 
      
 12 
     | 
    
         
            +
               * @param {object} res - The response object from the framework.
         
     | 
| 
      
 13 
     | 
    
         
            +
               * @returns {Object} Methods for manipulating server-sent events.
         
     | 
| 
      
 14 
     | 
    
         
            +
               */
         
     | 
| 
      
 15 
     | 
    
         
            +
              init: function (request, response) {
         
     | 
| 
      
 16 
     | 
    
         
            +
                return {
         
     | 
| 
      
 17 
     | 
    
         
            +
                  headersSent: false,
         
     | 
| 
      
 18 
     | 
    
         
            +
                  req: request,
         
     | 
| 
      
 19 
     | 
    
         
            +
                  res: response,
         
     | 
| 
      
 20 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 21 
     | 
    
         
            +
                   * @typedef {Object} SendOptions
         
     | 
| 
      
 22 
     | 
    
         
            +
                   * @property {?string} [eventId=null] - Event ID to attach.
         
     | 
| 
      
 23 
     | 
    
         
            +
                   * @property {number} [retryDuration=1000] - Retry duration in milliseconds.
         
     | 
| 
      
 24 
     | 
    
         
            +
                   */
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 27 
     | 
    
         
            +
                   * Sends a server-sent event (SSE) to the client.
         
     | 
| 
      
 28 
     | 
    
         
            +
                   *
         
     | 
| 
      
 29 
     | 
    
         
            +
                   * @param {string} eventType - The type of the event.
         
     | 
| 
      
 30 
     | 
    
         
            +
                   * @param {string[]} dataLines - Lines of data to send.
         
     | 
| 
      
 31 
     | 
    
         
            +
                   * @param {SendOptions} [sendOptions] - Additional options for sending events.
         
     | 
| 
      
 32 
     | 
    
         
            +
                   */
         
     | 
| 
      
 33 
     | 
    
         
            +
                  _send: function (
         
     | 
| 
      
 34 
     | 
    
         
            +
                    eventType,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    dataLines,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    sendOptions = {
         
     | 
| 
      
 37 
     | 
    
         
            +
                      eventId: null,
         
     | 
| 
      
 38 
     | 
    
         
            +
                      retryDuration: 1000,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  ) {
         
     | 
| 
      
 41 
     | 
    
         
            +
                    //Prepare the message for sending.
         
     | 
| 
      
 42 
     | 
    
         
            +
                    let data = dataLines.map((line) => `data: ${line}\n`).join("") + "\n";
         
     | 
| 
      
 43 
     | 
    
         
            +
                    let eventString = "";
         
     | 
| 
      
 44 
     | 
    
         
            +
                    if (sendOptions.eventId != null) {
         
     | 
| 
      
 45 
     | 
    
         
            +
                      eventString += `id: ${sendOptions.eventId}\n`;
         
     | 
| 
      
 46 
     | 
    
         
            +
                    }
         
     | 
| 
      
 47 
     | 
    
         
            +
                    if (eventType) {
         
     | 
| 
      
 48 
     | 
    
         
            +
                      eventString += `event: ${eventType}\n`;
         
     | 
| 
      
 49 
     | 
    
         
            +
                    }
         
     | 
| 
      
 50 
     | 
    
         
            +
                    eventString += `retry: ${sendOptions.retryDuration}\n`;
         
     | 
| 
      
 51 
     | 
    
         
            +
                    eventString += data;
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    //Send Event
         
     | 
| 
      
 54 
     | 
    
         
            +
                    if (!this.headersSent) {
         
     | 
| 
      
 55 
     | 
    
         
            +
                      this.res.setHeader("Cache-Control", "nocache");
         
     | 
| 
      
 56 
     | 
    
         
            +
                      this.res.setHeader("Connection", "keep-alive");
         
     | 
| 
      
 57 
     | 
    
         
            +
                      this.res.setHeader("Content-Type", "text/event-stream");
         
     | 
| 
      
 58 
     | 
    
         
            +
                      this.headersSent = true;
         
     | 
| 
      
 59 
     | 
    
         
            +
                    }
         
     | 
| 
      
 60 
     | 
    
         
            +
                    this.res.write(eventString);
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    return eventString;
         
     | 
| 
      
 63 
     | 
    
         
            +
                  },
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 66 
     | 
    
         
            +
                   * Reads signals based on HTTP methods and merges them with provided signals.
         
     | 
| 
      
 67 
     | 
    
         
            +
                   *
         
     | 
| 
      
 68 
     | 
    
         
            +
                   * @param {object} signals - Predefined signals to merge with.
         
     | 
| 
      
 69 
     | 
    
         
            +
                   * @returns {Promise<object>} Merged signals object.
         
     | 
| 
      
 70 
     | 
    
         
            +
                   */
         
     | 
| 
      
 71 
     | 
    
         
            +
                  ReadSignals: async function (signals) {
         
     | 
| 
      
 72 
     | 
    
         
            +
                    if (this.req.method === "GET") {
         
     | 
| 
      
 73 
     | 
    
         
            +
                      // Parse the URL
         
     | 
| 
      
 74 
     | 
    
         
            +
                      const parsedUrl = url.parse(this.req.url);
         
     | 
| 
      
 75 
     | 
    
         
            +
                      const parsedQuery = querystring.parse(parsedUrl.query);
         
     | 
| 
      
 76 
     | 
    
         
            +
                      const datastarParam = parsedQuery.datastar;
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                      const query = JSON.parse(datastarParam);
         
     | 
| 
      
 79 
     | 
    
         
            +
                      return {
         
     | 
| 
      
 80 
     | 
    
         
            +
                        ...signals,
         
     | 
| 
      
 81 
     | 
    
         
            +
                        ...query,
         
     | 
| 
      
 82 
     | 
    
         
            +
                      };
         
     | 
| 
      
 83 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 84 
     | 
    
         
            +
                      const body = await new Promise((resolve, reject) => {
         
     | 
| 
      
 85 
     | 
    
         
            +
                        let chunks = "";
         
     | 
| 
      
 86 
     | 
    
         
            +
                        this.req.on("data", (chunk) => {
         
     | 
| 
      
 87 
     | 
    
         
            +
                          chunks += chunk;
         
     | 
| 
      
 88 
     | 
    
         
            +
                        });
         
     | 
| 
      
 89 
     | 
    
         
            +
                        this.req.on("end", () => {
         
     | 
| 
      
 90 
     | 
    
         
            +
                          console.log("No more data in response.");
         
     | 
| 
      
 91 
     | 
    
         
            +
                          resolve(chunks);
         
     | 
| 
      
 92 
     | 
    
         
            +
                        });
         
     | 
| 
      
 93 
     | 
    
         
            +
                      });
         
     | 
| 
      
 94 
     | 
    
         
            +
                      let parsedBody = {};
         
     | 
| 
      
 95 
     | 
    
         
            +
                      try {
         
     | 
| 
      
 96 
     | 
    
         
            +
                        parsedBody = JSON.parse(body);
         
     | 
| 
      
 97 
     | 
    
         
            +
                      } catch (err) {
         
     | 
| 
      
 98 
     | 
    
         
            +
                        console.error(
         
     | 
| 
      
 99 
     | 
    
         
            +
                          "Problem reading signals, could not parse body as JSON."
         
     | 
| 
      
 100 
     | 
    
         
            +
                        );
         
     | 
| 
      
 101 
     | 
    
         
            +
                      }
         
     | 
| 
      
 102 
     | 
    
         
            +
                      console.log("parsed Body", parsedBody);
         
     | 
| 
      
 103 
     | 
    
         
            +
                      return { ...signals, ...parsedBody };
         
     | 
| 
      
 104 
     | 
    
         
            +
                    }
         
     | 
| 
      
 105 
     | 
    
         
            +
                  },
         
     | 
| 
      
 106 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 107 
     | 
    
         
            +
                   * @typedef {Object} MergeFragmentsOptions
         
     | 
| 
      
 108 
     | 
    
         
            +
                   * @property {string} [selector] - CSS selector affected.
         
     | 
| 
      
 109 
     | 
    
         
            +
                   * @property {string} [mergeMode="morph"] - Mode for merging.
         
     | 
| 
      
 110 
     | 
    
         
            +
                   * @property {number} [settleDuration=300] - Duration to settle.
         
     | 
| 
      
 111 
     | 
    
         
            +
                   * @property {?boolean} [useViewTransition=null] - Use view transition.
         
     | 
| 
      
 112 
     | 
    
         
            +
                   * @property {?string} [eventId=null] - Event ID to attach.
         
     | 
| 
      
 113 
     | 
    
         
            +
                   * @property {?number} [retryDuration=null] - Retry duration in milliseconds.
         
     | 
| 
      
 114 
     | 
    
         
            +
                   */
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 117 
     | 
    
         
            +
                   * Sends a merge fragments event.
         
     | 
| 
      
 118 
     | 
    
         
            +
                   *
         
     | 
| 
      
 119 
     | 
    
         
            +
                   * @param {string[]} fragments - Array of fragment identifiers.
         
     | 
| 
      
 120 
     | 
    
         
            +
                   * @param {MergeFragmentsOptions} options - Additional options for merging.
         
     | 
| 
      
 121 
     | 
    
         
            +
                   * @throws Will throw an error if fragments are missing.
         
     | 
| 
      
 122 
     | 
    
         
            +
                   */
         
     | 
| 
      
 123 
     | 
    
         
            +
                  MergeFragments: function (
         
     | 
| 
      
 124 
     | 
    
         
            +
                    fragments,
         
     | 
| 
      
 125 
     | 
    
         
            +
                    options = {
         
     | 
| 
      
 126 
     | 
    
         
            +
                      selector: null,
         
     | 
| 
      
 127 
     | 
    
         
            +
                      mergeMode: "morph",
         
     | 
| 
      
 128 
     | 
    
         
            +
                      settleDuration: 300,
         
     | 
| 
      
 129 
     | 
    
         
            +
                      useViewTransition: null,
         
     | 
| 
      
 130 
     | 
    
         
            +
                      eventId: null,
         
     | 
| 
      
 131 
     | 
    
         
            +
                      retryDuration: null,
         
     | 
| 
      
 132 
     | 
    
         
            +
                    }
         
     | 
| 
      
 133 
     | 
    
         
            +
                  ) {
         
     | 
| 
      
 134 
     | 
    
         
            +
                    let dataLines = [];
         
     | 
| 
      
 135 
     | 
    
         
            +
                    if (options?.selector != null)
         
     | 
| 
      
 136 
     | 
    
         
            +
                      dataLines.push(`selector ${options.selector}`);
         
     | 
| 
      
 137 
     | 
    
         
            +
                    if (options?.settleDuration != null)
         
     | 
| 
      
 138 
     | 
    
         
            +
                      dataLines.push(`settleDuration ${options.settleDuration}`);
         
     | 
| 
      
 139 
     | 
    
         
            +
                    if (options?.useViewTransition != null)
         
     | 
| 
      
 140 
     | 
    
         
            +
                      dataLines.push(`useViewTransition ${options.useViewTransition}`);
         
     | 
| 
      
 141 
     | 
    
         
            +
                    if (fragments) {
         
     | 
| 
      
 142 
     | 
    
         
            +
                      if (typeof fragments === "string") {
         
     | 
| 
      
 143 
     | 
    
         
            +
                        // Handle case where 'fragments' is a string
         
     | 
| 
      
 144 
     | 
    
         
            +
                        dataLines.push(`fragments ${fragments.replace(/[\r\n]+/g, "")}`);
         
     | 
| 
      
 145 
     | 
    
         
            +
                      } else if (Array.isArray(fragments)) {
         
     | 
| 
      
 146 
     | 
    
         
            +
                        // Handle case where 'fragments' is an array
         
     | 
| 
      
 147 
     | 
    
         
            +
                        fragments.forEach((frag) => {
         
     | 
| 
      
 148 
     | 
    
         
            +
                          dataLines.push(`fragments ${frag.replace(/[\r\n]+/g, "")}`);
         
     | 
| 
      
 149 
     | 
    
         
            +
                        });
         
     | 
| 
      
 150 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 151 
     | 
    
         
            +
                        throw Error(
         
     | 
| 
      
 152 
     | 
    
         
            +
                          "Invalid type for fragments. Expected string or array."
         
     | 
| 
      
 153 
     | 
    
         
            +
                        );
         
     | 
| 
      
 154 
     | 
    
         
            +
                      }
         
     | 
| 
      
 155 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 156 
     | 
    
         
            +
                      throw Error("MergeFragments missing fragment(s).");
         
     | 
| 
      
 157 
     | 
    
         
            +
                    }
         
     | 
| 
      
 158 
     | 
    
         
            +
                    return this._send("datastar-merge-fragments", dataLines, {
         
     | 
| 
      
 159 
     | 
    
         
            +
                      eventId: options?.eventId,
         
     | 
| 
      
 160 
     | 
    
         
            +
                      retryDuration: options?.retryDuration,
         
     | 
| 
      
 161 
     | 
    
         
            +
                    });
         
     | 
| 
      
 162 
     | 
    
         
            +
                  },
         
     | 
| 
      
 163 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 164 
     | 
    
         
            +
                   * @typedef {Object} RemoveFragmentsOptions
         
     | 
| 
      
 165 
     | 
    
         
            +
                   * @property {number} [settleDuration] - Duration to settle.
         
     | 
| 
      
 166 
     | 
    
         
            +
                   * @property {?boolean} [useViewTransition=null] - Use view transition.
         
     | 
| 
      
 167 
     | 
    
         
            +
                   * @property {?string} [eventId=null] - Event ID to attach.
         
     | 
| 
      
 168 
     | 
    
         
            +
                   * @property {?number} [retryDuration=null] - Retry duration in milliseconds.
         
     | 
| 
      
 169 
     | 
    
         
            +
                   */
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 172 
     | 
    
         
            +
                   * Sends a remove fragments event.
         
     | 
| 
      
 173 
     | 
    
         
            +
                   *
         
     | 
| 
      
 174 
     | 
    
         
            +
                   * @param {string} selector - CSS selector of fragments to remove.
         
     | 
| 
      
 175 
     | 
    
         
            +
                   * @param {RemoveFragmentsOptions} options - Additional options for removing.
         
     | 
| 
      
 176 
     | 
    
         
            +
                   * @throws Will throw an error if selector is missing.
         
     | 
| 
      
 177 
     | 
    
         
            +
                   */
         
     | 
| 
      
 178 
     | 
    
         
            +
                  RemoveFragments: function (selector, options) {
         
     | 
| 
      
 179 
     | 
    
         
            +
                    let dataLines = [];
         
     | 
| 
      
 180 
     | 
    
         
            +
                    if (selector) {
         
     | 
| 
      
 181 
     | 
    
         
            +
                      dataLines.push(`selector ${selector}`);
         
     | 
| 
      
 182 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 183 
     | 
    
         
            +
                      throw Error("RemoveFragments missing selector.");
         
     | 
| 
      
 184 
     | 
    
         
            +
                    }
         
     | 
| 
      
 185 
     | 
    
         
            +
                    if (options?.settleDuration != null)
         
     | 
| 
      
 186 
     | 
    
         
            +
                      dataLines.push(`settleDuration ${options.settleDuration}`);
         
     | 
| 
      
 187 
     | 
    
         
            +
                    if (options?.useViewTransition != null)
         
     | 
| 
      
 188 
     | 
    
         
            +
                      dataLines.push(`useViewTransition ${options.useViewTransition}`);
         
     | 
| 
      
 189 
     | 
    
         
            +
                    return this._send(`datastar-remove-fragments`, dataLines, {
         
     | 
| 
      
 190 
     | 
    
         
            +
                      eventId: options?.eventId,
         
     | 
| 
      
 191 
     | 
    
         
            +
                      retryDuration: options?.retryDuration,
         
     | 
| 
      
 192 
     | 
    
         
            +
                    });
         
     | 
| 
      
 193 
     | 
    
         
            +
                  },
         
     | 
| 
      
 194 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 195 
     | 
    
         
            +
                   * @typedef {Object} MergeSignalsOptions
         
     | 
| 
      
 196 
     | 
    
         
            +
                   * @property {boolean} [onlyIfMissing] - Merge only if signals are missing.
         
     | 
| 
      
 197 
     | 
    
         
            +
                   * @property {?string} [eventId=null] - Event ID to attach.
         
     | 
| 
      
 198 
     | 
    
         
            +
                   * @property {?number} [retryDuration=null] - Retry duration in milliseconds.
         
     | 
| 
      
 199 
     | 
    
         
            +
                   */
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 202 
     | 
    
         
            +
                   * Sends a merge signals event.
         
     | 
| 
      
 203 
     | 
    
         
            +
                   *
         
     | 
| 
      
 204 
     | 
    
         
            +
                   * @param {object} signals - Signals to merge.
         
     | 
| 
      
 205 
     | 
    
         
            +
                   * @param {MergeSignalsOptions} options - Additional options for merging.
         
     | 
| 
      
 206 
     | 
    
         
            +
                   * @throws Will throw an error if signals are missing.
         
     | 
| 
      
 207 
     | 
    
         
            +
                   */
         
     | 
| 
      
 208 
     | 
    
         
            +
                  MergeSignals: function (signals, options) {
         
     | 
| 
      
 209 
     | 
    
         
            +
                    let dataLines = [];
         
     | 
| 
      
 210 
     | 
    
         
            +
                    if (options?.onlyIfMissing === true) {
         
     | 
| 
      
 211 
     | 
    
         
            +
                      dataLines.push(`onlyIfMissing true`);
         
     | 
| 
      
 212 
     | 
    
         
            +
                    }
         
     | 
| 
      
 213 
     | 
    
         
            +
                    if (signals) {
         
     | 
| 
      
 214 
     | 
    
         
            +
                      dataLines.push(`signals ${JSON.stringify(signals)}`);
         
     | 
| 
      
 215 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 216 
     | 
    
         
            +
                      throw Error("MergeSignals missing signals.");
         
     | 
| 
      
 217 
     | 
    
         
            +
                    }
         
     | 
| 
      
 218 
     | 
    
         
            +
                    return this._send(`datastar-merge-signals`, dataLines, {
         
     | 
| 
      
 219 
     | 
    
         
            +
                      eventId: options?.eventId,
         
     | 
| 
      
 220 
     | 
    
         
            +
                      retryDuration: options?.retryDuration,
         
     | 
| 
      
 221 
     | 
    
         
            +
                    });
         
     | 
| 
      
 222 
     | 
    
         
            +
                  },
         
     | 
| 
      
 223 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 224 
     | 
    
         
            +
                   * Sends a remove signals event.
         
     | 
| 
      
 225 
     | 
    
         
            +
                   *
         
     | 
| 
      
 226 
     | 
    
         
            +
                   * @param {string[]} paths - Paths of signals to remove.
         
     | 
| 
      
 227 
     | 
    
         
            +
                   * @param {SendOptions} options - Additional options for removing signals.
         
     | 
| 
      
 228 
     | 
    
         
            +
                   * @throws Will throw an error if paths are missing.
         
     | 
| 
      
 229 
     | 
    
         
            +
                   */
         
     | 
| 
      
 230 
     | 
    
         
            +
                  RemoveSignals: function (paths, options) {
         
     | 
| 
      
 231 
     | 
    
         
            +
                    let dataLines = [];
         
     | 
| 
      
 232 
     | 
    
         
            +
                    if (paths) {
         
     | 
| 
      
 233 
     | 
    
         
            +
                      paths
         
     | 
| 
      
 234 
     | 
    
         
            +
                        .map((path) => {
         
     | 
| 
      
 235 
     | 
    
         
            +
                          dataLines.push(`paths ${path}`);
         
     | 
| 
      
 236 
     | 
    
         
            +
                        })
         
     | 
| 
      
 237 
     | 
    
         
            +
                        .join("");
         
     | 
| 
      
 238 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 239 
     | 
    
         
            +
                      throw Error("RemoveSignals missing paths");
         
     | 
| 
      
 240 
     | 
    
         
            +
                    }
         
     | 
| 
      
 241 
     | 
    
         
            +
                    return this._send(`datastar-remove-signals`, dataLines, {
         
     | 
| 
      
 242 
     | 
    
         
            +
                      eventId: options?.eventId,
         
     | 
| 
      
 243 
     | 
    
         
            +
                      retryDuration: options?.retryDuration,
         
     | 
| 
      
 244 
     | 
    
         
            +
                    });
         
     | 
| 
      
 245 
     | 
    
         
            +
                  },
         
     | 
| 
      
 246 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 247 
     | 
    
         
            +
                   * @typedef {Object} ExecuteScriptOptions
         
     | 
| 
      
 248 
     | 
    
         
            +
                   * @property {boolean} [autoRemove] - Automatically remove the script after execution.
         
     | 
| 
      
 249 
     | 
    
         
            +
                   * @property {?string} [eventId=null] - Event ID to attach.
         
     | 
| 
      
 250 
     | 
    
         
            +
                   * @property {?number} [retryDuration=null] - Retry duration in milliseconds.
         
     | 
| 
      
 251 
     | 
    
         
            +
                   */
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                  /**
         
     | 
| 
      
 254 
     | 
    
         
            +
                   * Executes a script on the client-side.
         
     | 
| 
      
 255 
     | 
    
         
            +
                   *
         
     | 
| 
      
 256 
     | 
    
         
            +
                   * @param {string} script - Script code to execute.
         
     | 
| 
      
 257 
     | 
    
         
            +
                   * @param {ExecuteScriptOptions} options - Additional options for execution.
         
     | 
| 
      
 258 
     | 
    
         
            +
                   */
         
     | 
| 
      
 259 
     | 
    
         
            +
                  ExecuteScript: function (script, options) {
         
     | 
| 
      
 260 
     | 
    
         
            +
                    let dataLines = [];
         
     | 
| 
      
 261 
     | 
    
         
            +
                    if (options?.autoRemove != null)
         
     | 
| 
      
 262 
     | 
    
         
            +
                      dataLines.push(`autoRemove ${options.autoRemove}`);
         
     | 
| 
      
 263 
     | 
    
         
            +
                    if (script) {
         
     | 
| 
      
 264 
     | 
    
         
            +
                      dataLines.push(`script ${script}`);
         
     | 
| 
      
 265 
     | 
    
         
            +
                    }
         
     | 
| 
      
 266 
     | 
    
         
            +
                    return this._send(`datastar-execute-script`, dataLines, {
         
     | 
| 
      
 267 
     | 
    
         
            +
                      eventId: options?.eventId,
         
     | 
| 
      
 268 
     | 
    
         
            +
                      retryDuration: options?.retryDuration,
         
     | 
| 
      
 269 
     | 
    
         
            +
                    });
         
     | 
| 
      
 270 
     | 
    
         
            +
                  },
         
     | 
| 
      
 271 
     | 
    
         
            +
                };
         
     | 
| 
      
 272 
     | 
    
         
            +
              },
         
     | 
| 
      
 273 
     | 
    
         
            +
            };
         
     | 
    
        package/package.json
    ADDED
    
    | 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            {
         
     | 
| 
      
 2 
     | 
    
         
            +
              "name": "datastar-ssegen",
         
     | 
| 
      
 3 
     | 
    
         
            +
              "version": "0.0.1",
         
     | 
| 
      
 4 
     | 
    
         
            +
              "description": "Datastar Server-Sent Event generator",
         
     | 
| 
      
 5 
     | 
    
         
            +
              "author": "John Cudd",
         
     | 
| 
      
 6 
     | 
    
         
            +
              "type": "module",
         
     | 
| 
      
 7 
     | 
    
         
            +
              "main": "index.js",
         
     | 
| 
      
 8 
     | 
    
         
            +
              "scripts": {
         
     | 
| 
      
 9 
     | 
    
         
            +
                "dev": "concurrently -c \"red,green,blue\" -n \"node,express,hyper-express\" \"npm run node\" \"npm run express\" \"npm run hyper-express\"",
         
     | 
| 
      
 10 
     | 
    
         
            +
                "node": "nodemon examples/node.example.js",
         
     | 
| 
      
 11 
     | 
    
         
            +
                "express": "nodemon examples/express.example.js",
         
     | 
| 
      
 12 
     | 
    
         
            +
                "hyper-express": "nodemon examples/hyper-express.example.js"
         
     | 
| 
      
 13 
     | 
    
         
            +
              },
         
     | 
| 
      
 14 
     | 
    
         
            +
              "keywords": ["datastar", "hypermedia", "sse"],
         
     | 
| 
      
 15 
     | 
    
         
            +
              "license": "mit",
         
     | 
| 
      
 16 
     | 
    
         
            +
              "homepage": "https://github.com/jmcudd/datastar-ssegen#readme",
         
     | 
| 
      
 17 
     | 
    
         
            +
              "repository": {
         
     | 
| 
      
 18 
     | 
    
         
            +
                "type": "git",
         
     | 
| 
      
 19 
     | 
    
         
            +
                "url": "git+https://github.com/jmcudd/datastar-ssegen.git"
         
     | 
| 
      
 20 
     | 
    
         
            +
              },
         
     | 
| 
      
 21 
     | 
    
         
            +
              "bugs": {
         
     | 
| 
      
 22 
     | 
    
         
            +
                "url": "https://github.com/jmcudd/datastar-ssegen/issues"
         
     | 
| 
      
 23 
     | 
    
         
            +
              },
         
     | 
| 
      
 24 
     | 
    
         
            +
              "devdependencies": {
         
     | 
| 
      
 25 
     | 
    
         
            +
                "concurrently": "^9.1.0",
         
     | 
| 
      
 26 
     | 
    
         
            +
                "express": "^4.21.2",
         
     | 
| 
      
 27 
     | 
    
         
            +
                "hyper-express": "^6.17.3",
         
     | 
| 
      
 28 
     | 
    
         
            +
                "nodemon": "^3.1.9",
         
     | 
| 
      
 29 
     | 
    
         
            +
                "npm-run-all": "^4.1.5"
         
     | 
| 
      
 30 
     | 
    
         
            +
              }
         
     | 
| 
      
 31 
     | 
    
         
            +
            }
         
     |