datastar-ssegen 1.0.2 → 1.2.0
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/README.md +10 -8
- package/datastarVersion.js +2 -0
- package/examples/bun.example.js +5 -3
- package/examples/commonHandlers.js +11 -10
- package/index.js +2 -75
- package/jsconfig.json +1 -1
- package/package.json +1 -1
- package/types.d.ts +65 -0
package/README.md
CHANGED
@@ -5,10 +5,12 @@
|
|
5
5
|
|
6
6
|
## Overview
|
7
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, and Bun and Elysia.
|
8
|
+
The `datastar-ssegen` is a backend JavaScript module designed to generate Server-Sent Events (SSE) for connected [Datastar](https://data-star.dev/) (v1.0.0-beta.1) clients. It supports popular server frameworks such as Express.js, Node.js, and Hyper Express.js, and Bun and Elysia.
|
9
9
|
|
10
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
11
|
|
12
|
+
Tested with datastar `v1.0.0-beta.9`.
|
13
|
+
|
12
14
|
### Key Features
|
13
15
|
|
14
16
|
- Real-time updates with Server-Sent Events tailored for Datastar clients
|
@@ -69,13 +71,13 @@ Here's a simple HTML page to interact with the server:
|
|
69
71
|
<meta charset="UTF-8">
|
70
72
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
71
73
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
72
|
-
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar/bundles/datastar.js"></script>
|
74
|
+
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.0-beta.1/bundles/datastar.js"></script>
|
73
75
|
<title>SSE Example</title>
|
74
76
|
</head>
|
75
77
|
<body>
|
76
78
|
<h1>SSE Demo</h1>
|
77
|
-
<div id="qoute" data-on-load="
|
78
|
-
<div id="clock" data-on-load="
|
79
|
+
<div id="qoute" data-on-load="@get('/qoute')">Qoute: </div><button onclick="@get('/qoute')">Get New Qoute</button>
|
80
|
+
<div id="clock" data-on-load="@get('/clock')"></div>
|
79
81
|
</body>
|
80
82
|
</html>
|
81
83
|
```
|
@@ -95,9 +97,9 @@ const app = new Elysia()
|
|
95
97
|
() =>
|
96
98
|
`<html>
|
97
99
|
<head>
|
98
|
-
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar/bundles/datastar.js"></script>
|
100
|
+
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.0-beta.1/bundles/datastar.js"></script>
|
99
101
|
</head>
|
100
|
-
<body data-on-load="
|
102
|
+
<body data-on-load="@get('/feed')">
|
101
103
|
<div id="hello">???</div>
|
102
104
|
</body>
|
103
105
|
</html>`
|
@@ -133,9 +135,9 @@ Bun.serve({
|
|
133
135
|
`<html>
|
134
136
|
<head>
|
135
137
|
<title>Example Bun</title>
|
136
|
-
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar/bundles/datastar.js"></script>
|
138
|
+
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.0-beta.1/bundles/datastar.js"></script>
|
137
139
|
</head>
|
138
|
-
<body data-signals="{time:''}" data-on-load="
|
140
|
+
<body data-signals="{time:''}" data-on-load="@get('/feed')">
|
139
141
|
<div data-text="time.value"></div>
|
140
142
|
</body>
|
141
143
|
</html>`,
|
package/examples/bun.example.js
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
import { ServerSentEventGenerator } from "../index.js";
|
2
|
+
import { datastarVersion } from "../datastarVersion.js";
|
3
|
+
|
2
4
|
const PORT = 3103;
|
3
5
|
console.log(`Bun server http://localhost:${PORT}`);
|
4
6
|
Bun.serve({
|
@@ -11,10 +13,10 @@ Bun.serve({
|
|
11
13
|
`<html>
|
12
14
|
<head>
|
13
15
|
<title>Example Bun</title>
|
14
|
-
<script type="module" src="
|
16
|
+
<script type="module" src="${datastarVersion}"></script>
|
15
17
|
</head>
|
16
|
-
<body data-signals="{time:''}" data-on-load="
|
17
|
-
<div data-text="time
|
18
|
+
<body data-signals="{time:''}" data-on-load="@get('/feed')">
|
19
|
+
<div data-text="$time"></div>
|
18
20
|
</body>
|
19
21
|
</html>`,
|
20
22
|
{
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { ServerSentEventGenerator } from "../index.js";
|
2
|
+
import { datastarVersion } from "../datastarVersion.js";
|
2
3
|
|
3
4
|
export let backendStore = {
|
4
5
|
someBackendValue: "This is something",
|
@@ -7,38 +8,38 @@ export const homepage = (name = "") => {
|
|
7
8
|
return `<html>
|
8
9
|
<head>
|
9
10
|
<title>${name} Datastar Test</title>
|
10
|
-
<script type="module" src="
|
11
|
+
<script type="module" src="${datastarVersion}"></script>
|
11
12
|
</head>
|
12
13
|
<body>
|
13
14
|
<h3>${name} Datastar Test</h3>
|
14
15
|
<div data-signals="{theme: 'light', lastUpdate:'Never', xyz:'some signal'}">
|
15
16
|
<h3>Long Lived SSE:</h3>
|
16
|
-
<div id="clock" data-on-load="
|
17
|
+
<div id="clock" data-on-load="@get('/clock')">...Loading Clock</div>
|
17
18
|
|
18
19
|
<h3>MergeSignals:</h3>
|
19
|
-
<div>Last User Interaction:<span data-text="lastUpdate
|
20
|
+
<div>Last User Interaction:<span data-text="$lastUpdate"></span></div>
|
20
21
|
<h3>Merge Fragments</h3>
|
21
22
|
<div id="quote">No Quote</div>
|
22
|
-
<button data-on-click="
|
23
|
+
<button data-on-click="@get('/quote')">MergeFragments</button>
|
23
24
|
<h3>RemoveFragments</h3>
|
24
25
|
<div id="trash">
|
25
26
|
Remove me please!
|
26
|
-
<button data-on-click="
|
27
|
+
<button data-on-click="@get('/removeTrash')">RemoveFragments</button>
|
27
28
|
</div>
|
28
29
|
<h3>ExecuteScript</h3>
|
29
30
|
<div>Print to Console</div>
|
30
|
-
<button data-on-click="
|
31
|
+
<button data-on-click="@get('/printToConsole')">ExecuteScript</button>
|
31
32
|
|
32
33
|
<h3>ReadSignals</h3>
|
33
|
-
<button data-on-click="
|
34
|
+
<button data-on-click="@get('/readSignals')">ReadSignals</button>
|
34
35
|
|
35
36
|
<h3>ReadSignals (post)</h3>
|
36
|
-
<button data-on-click="
|
37
|
+
<button data-on-click="@get('/readSignals', {method: 'post'})">ReadSignals (post)</button>
|
37
38
|
|
38
39
|
|
39
40
|
<h3>RemoveSignals</h3>
|
40
|
-
<div>Signal xyz:<span data-text="xyz
|
41
|
-
<button data-on-click="
|
41
|
+
<div>Signal xyz:<span data-text="$xyz"></span></div>
|
42
|
+
<button data-on-click="@get('/removeSignal')">Test RemoveSignals: xyz</button>
|
42
43
|
</div>
|
43
44
|
</body>
|
44
45
|
</html>`;
|
package/index.js
CHANGED
@@ -2,81 +2,6 @@
|
|
2
2
|
import url from "url";
|
3
3
|
import querystring from "querystring";
|
4
4
|
|
5
|
-
/**
|
6
|
-
* @typedef {object} ServerSentEventMethods
|
7
|
-
* @property {Function} _send - Sends a server-sent event.
|
8
|
-
* @property {Function} ReadSignals - Reads signals based on HTTP methods and merges them with predefined signals.
|
9
|
-
* @property {Function} MergeFragments - Sends a merge fragments event with specified options.
|
10
|
-
* @property {Function} RemoveFragments - Sends a remove fragments event.
|
11
|
-
* @property {Function} MergeSignals - Sends a merge signals event, with merging options.
|
12
|
-
* @property {Function} RemoveSignals - Sends a remove signals event, requires signal paths.
|
13
|
-
* @property {Function} ExecuteScript - Executes a defined script on the client-side.
|
14
|
-
*/
|
15
|
-
|
16
|
-
/**
|
17
|
-
* @typedef {object} SendOptions
|
18
|
-
* @property {number|null} [eventId] - The ID of the event.
|
19
|
-
* @property {number|null} [retryDuration] - Duration in milliseconds to wait before attempting a retry.
|
20
|
-
*/
|
21
|
-
|
22
|
-
/**
|
23
|
-
* @typedef {object} MergeFragmentsOptions
|
24
|
-
* @property {string|null} [selector] - CSS selector to scope the merge action.
|
25
|
-
* @property {string} [mergeMode=morph] - Mode to use for merging fragments.
|
26
|
-
* @property {number} [settleDuration=300] - Duration for settling the merge.
|
27
|
-
* @property {boolean|null} [useViewTransition] - Use CSS view transitions if supported.
|
28
|
-
* @property {number|null} [eventId] - Event ID for the merge fragments event.
|
29
|
-
* @property {number|null} [retryDuration] - Retry duration for the event.
|
30
|
-
*/
|
31
|
-
|
32
|
-
/**
|
33
|
-
* @typedef {object} RemoveFragmentsOptions
|
34
|
-
* @property {number} [settleDuration] - Duration for settling the removal.
|
35
|
-
* @property {boolean|null} [useViewTransition] - Use CSS view transitions if supported.
|
36
|
-
* @property {number|null} [eventId] - Event ID for the remove fragments event.
|
37
|
-
* @property {number|null} [retryDuration] - Retry duration for the event.
|
38
|
-
*/
|
39
|
-
|
40
|
-
/**
|
41
|
-
* @typedef {object} MergeSignalsOptions
|
42
|
-
* @property {boolean} [onlyIfMissing=false] - Merge only if the signal is missing.
|
43
|
-
* @property {number|null} [eventId] - Event ID for the merge signals event.
|
44
|
-
* @property {number|null} [retryDuration] - Retry duration for the event.
|
45
|
-
*/
|
46
|
-
|
47
|
-
/**
|
48
|
-
* @typedef {object} ExecuteScriptOptions
|
49
|
-
* @property {boolean|null} [autoRemove] - Automatically remove the script after execution.
|
50
|
-
* @property {number|null} [eventId] - Event ID for the execute script event.
|
51
|
-
* @property {number|null} [retryDuration] - Retry duration for the event.
|
52
|
-
*/
|
53
|
-
|
54
|
-
/**
|
55
|
-
* @typedef {Object} HttpRequest
|
56
|
-
* @property {string} method - The HTTP method, e.g., 'GET', 'POST', etc.
|
57
|
-
* @property {string} url - The URL of the request.
|
58
|
-
* @property {Object.<string, string>} headers - The HTTP headers.
|
59
|
-
* @property {Object} [body] - The payload of the request.
|
60
|
-
* @property {Function} [json] - Parses the request body
|
61
|
-
* @property {Function} [on] - Adds event handlers to the request
|
62
|
-
*/
|
63
|
-
|
64
|
-
/**
|
65
|
-
* @typedef {Object} HttpResponse
|
66
|
-
* @property {number} statusCode - The HTTP status code, e.g., 200, 404, etc.
|
67
|
-
* @property {Object.<string, string>} headers - The HTTP headers.
|
68
|
-
* @property {Object|string} [body] - The response body.
|
69
|
-
* @property {Function} setHeader - Sets a header on the response
|
70
|
-
* @property {Function} write - Writes to the response body
|
71
|
-
*/
|
72
|
-
|
73
|
-
/**
|
74
|
-
* Initializes the server-sent event generator.
|
75
|
-
*
|
76
|
-
* @param {HttpRequest} request - The request object.
|
77
|
-
* @param {HttpResponse} response - The response object.
|
78
|
-
* @returns {ServerSentEventMethods} Methods for manipulating server-sent events.
|
79
|
-
*/
|
80
5
|
export function ServerSentEventGenerator(request, response) {
|
81
6
|
const generatorMethods = {
|
82
7
|
headersSent: false,
|
@@ -193,6 +118,8 @@ export function ServerSentEventGenerator(request, response) {
|
|
193
118
|
let dataLines = [];
|
194
119
|
if (options?.selector != null)
|
195
120
|
dataLines.push(`selector ${options.selector}`);
|
121
|
+
if (options?.mergeMode != null)
|
122
|
+
dataLines.push(`mergeMode ${options.mergeMode}`);
|
196
123
|
if (options?.settleDuration != null)
|
197
124
|
dataLines.push(`settleDuration ${options.settleDuration}`);
|
198
125
|
if (options?.useViewTransition != null)
|
package/jsconfig.json
CHANGED
package/package.json
CHANGED
package/types.d.ts
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
type HttpRequest = {
|
2
|
+
method: string;
|
3
|
+
url: string;
|
4
|
+
headers: Record<string, string>;
|
5
|
+
body?: any;
|
6
|
+
json?: Function;
|
7
|
+
on?: Function;
|
8
|
+
};
|
9
|
+
|
10
|
+
type HttpResponse = {
|
11
|
+
statusCode: number;
|
12
|
+
headers: Record<string, string>;
|
13
|
+
body?: Record<string, string> | string;
|
14
|
+
setHeader: Function;
|
15
|
+
write: Function;
|
16
|
+
};
|
17
|
+
|
18
|
+
type SendOptions = {
|
19
|
+
eventId?: number | null;
|
20
|
+
retryDuration?: number | null;
|
21
|
+
};
|
22
|
+
|
23
|
+
type MergeFragmentsOptions = {
|
24
|
+
selector?: string | null;
|
25
|
+
mergeMode?: string;
|
26
|
+
settleDuration?: number;
|
27
|
+
useViewTransition?: boolean | null;
|
28
|
+
eventId?: number | null;
|
29
|
+
retryDuration?: number | null;
|
30
|
+
};
|
31
|
+
|
32
|
+
type RemoveFragmentsOptions = {
|
33
|
+
settleDuration?: number;
|
34
|
+
useViewTransition?: boolean | null;
|
35
|
+
eventId?: number | null;
|
36
|
+
retryDuration?: number | null;
|
37
|
+
};
|
38
|
+
|
39
|
+
type MergeSignalsOptions = {
|
40
|
+
onlyIfMissing?: boolean;
|
41
|
+
eventId?: number | null;
|
42
|
+
retryDuration?: number | null;
|
43
|
+
};
|
44
|
+
|
45
|
+
type ExecuteScriptOptions = {
|
46
|
+
autoRemove?: boolean | null;
|
47
|
+
eventId?: number | null;
|
48
|
+
retryDuration?: number | null;
|
49
|
+
};
|
50
|
+
|
51
|
+
type ServerSentEventMethods = {
|
52
|
+
_send: Function;
|
53
|
+
ReadSignals: (signals: object) => Promise<object>;
|
54
|
+
MergeFragments: (
|
55
|
+
fragments: string[] | string,
|
56
|
+
options: MergeFragmentsOptions
|
57
|
+
) => string;
|
58
|
+
RemoveFragments: (
|
59
|
+
selector: string,
|
60
|
+
options: RemoveFragmentsOptions
|
61
|
+
) => string;
|
62
|
+
MergeSignals: (signals: object, options: MergeSignalsOptions) => string;
|
63
|
+
RemoveSignals: (paths: string[], options: SendOptions) => string;
|
64
|
+
ExecuteScript: (script: string, options: ExecuteScriptOptions) => string;
|
65
|
+
};
|