@jay-framework/ssr-runtime 0.13.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.
@@ -0,0 +1,43 @@
1
+ /**
2
+ * HTML-escape a string for safe embedding in HTML content.
3
+ * Escapes: & < > " '
4
+ */
5
+ declare function escapeHtml(str: string): string;
6
+ /**
7
+ * HTML-escape a string for safe embedding in attribute values.
8
+ * Same escaping as escapeHtml — covers all characters that could break
9
+ * out of single-quoted, double-quoted, or unquoted attribute values.
10
+ */
11
+ declare function escapeAttr(str: string): string;
12
+
13
+ /**
14
+ * Context passed to compiled renderToStream functions.
15
+ * Provides `write` for streaming HTML chunks and `onAsync` for registering
16
+ * promise-based async content that will be swapped in via inline scripts.
17
+ */
18
+ interface ServerRenderContext {
19
+ /** Write an HTML chunk to the response stream. */
20
+ write: (chunk: string) => void;
21
+ /**
22
+ * Register an async promise for streaming resolution.
23
+ * The pending variant is rendered inline immediately.
24
+ * When the promise settles, the framework writes an inline script
25
+ * that swaps the pending content with resolved/rejected content.
26
+ */
27
+ onAsync: (promise: Promise<any>, id: string, templates: {
28
+ resolved?: (val: any) => string;
29
+ rejected?: (err: any) => string;
30
+ }) => void;
31
+ }
32
+
33
+ /**
34
+ * Generate an inline `<script>` that swaps a pending async placeholder
35
+ * with resolved/rejected HTML content.
36
+ *
37
+ * The generated script finds the element with `jay-async="id:pending"`,
38
+ * creates a temporary container, sets its innerHTML to the new HTML,
39
+ * and replaces the placeholder with the new content.
40
+ */
41
+ declare function asyncSwapScript(id: string, html: string): string;
42
+
43
+ export { type ServerRenderContext, asyncSwapScript, escapeAttr, escapeHtml };
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ const HTML_ESCAPE_MAP = {
2
+ "&": "&amp;",
3
+ "<": "&lt;",
4
+ ">": "&gt;",
5
+ '"': "&quot;",
6
+ "'": "&#39;"
7
+ };
8
+ const HTML_ESCAPE_RE = /[&<>"']/g;
9
+ function escapeHtml(str) {
10
+ return String(str).replace(HTML_ESCAPE_RE, (char) => HTML_ESCAPE_MAP[char]);
11
+ }
12
+ function escapeAttr(str) {
13
+ return String(str).replace(HTML_ESCAPE_RE, (char) => HTML_ESCAPE_MAP[char]);
14
+ }
15
+ function asyncSwapScript(id, html) {
16
+ const escapedHtml = html.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
17
+ return `<script>(function(){var t=document.querySelector('[jay-async="${id}:pending"]');if(t){var d=document.createElement('div');d.innerHTML='${escapedHtml}';t.replaceWith(d.firstChild);}window.__jay&&window.__jay.hydrateAsync&&window.__jay.hydrateAsync('${id}');})()<\/script>`;
18
+ }
19
+ export {
20
+ asyncSwapScript,
21
+ escapeAttr,
22
+ escapeHtml
23
+ };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@jay-framework/ssr-runtime",
3
+ "version": "0.13.0",
4
+ "type": "module",
5
+ "license": "Apache-2.0",
6
+ "main": "dist/index.js",
7
+ "files": [
8
+ "dist",
9
+ "readme.md"
10
+ ],
11
+ "scripts": {
12
+ "build": "npm run build:js && npm run build:types",
13
+ "build:watch": "npm run build:js -- --watch & npm run build:types -- --watch",
14
+ "build:js": "vite build",
15
+ "build:types": "tsup lib/index.ts --dts-only --format esm",
16
+ "build:check-types": "tsc",
17
+ "clean": "rimraf dist",
18
+ "confirm": "npm run clean && npm run build && npm run build:check-types && npm run test",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest"
21
+ },
22
+ "devDependencies": {
23
+ "@jay-framework/dev-environment": "^0.14.0",
24
+ "@types/node": "^20.11.5",
25
+ "rimraf": "^5.0.5",
26
+ "tsup": "^8.0.1",
27
+ "typescript": "^5.3.3",
28
+ "vite": "^5.0.11",
29
+ "vitest": "^1.2.1"
30
+ }
31
+ }