@jslop/server 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 p-arndt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # @jslop/server
2
+
3
+ SSR for JSlop components. Walks a compiled component's `buildView()` tree, emits HTML, and inlines the state capsule that `@jslop/client` resumes from.
4
+
5
+ ```bash
6
+ pnpm add @jslop/server
7
+ ```
8
+
9
+ ## API
10
+
11
+ ```ts
12
+ import { renderPage, renderView } from "@jslop/server";
13
+
14
+ const html = renderPage({
15
+ title: "My page",
16
+ component, // a __jslop_component (default export of a compiled .jslop)
17
+ props: { slug: "hello-world" },
18
+ appScriptUrl: "/client.js", // <script type="module" src="...">
19
+ stylesheets: ["/src/app.css"], // optional <link rel="stylesheet">
20
+ head: "<meta name=\"x\" content=\"y\">", // optional extra <head> HTML
21
+ });
22
+ ```
23
+
24
+ `renderView(node)` is the lower-level helper that turns a single `ViewNode` into an HTML string.
25
+
26
+ ## Output shape
27
+
28
+ ```html
29
+ <!doctype html>
30
+ <html>
31
+ <head>
32
+ <title>My page</title>
33
+ <link rel="stylesheet" href="/src/app.css">
34
+ </head>
35
+ <body>
36
+ <div id="__jslop_root">
37
+ <!-- rendered component HTML -->
38
+ </div>
39
+ <script id="__jslop_state" type="application/json">
40
+ { "count": 0, "children": [ ... ] }
41
+ </script>
42
+ <script type="module" src="/client.js"></script>
43
+ </body>
44
+ </html>
45
+ ```
46
+
47
+ The state capsule is plain JSON — `@jslop/client` reads it via `JSON.parse`. There is no class revival or function deserialization.
48
+
49
+ ## Known limitations
50
+
51
+ > [!CAUTION]
52
+ > - **Buffered.** The whole page is rendered to a string before responding. Streaming SSR isn't implemented.
53
+ > - **Whitespace.** Pure-whitespace text nodes still emit a space character — usually harmless but produces ugly HTML.
54
+
55
+ See [`TODO.md`](../../TODO.md) and [docs/ssr-and-resumability.md](../../docs/ssr-and-resumability.md).
@@ -0,0 +1,95 @@
1
+ export type RenderAttr = string | {
2
+ kind: "bind";
3
+ get: () => string;
4
+ } | {
5
+ kind: "prop";
6
+ get: () => unknown;
7
+ };
8
+ export type RenderNode = {
9
+ kind: "text";
10
+ value: string;
11
+ } | {
12
+ kind: "bind";
13
+ get: () => string;
14
+ } | {
15
+ kind: "component";
16
+ name: string;
17
+ instance: JSlopInstance;
18
+ view: RenderNode;
19
+ } | {
20
+ kind: "if";
21
+ test: () => unknown;
22
+ consequent: RenderNode[];
23
+ alternate: RenderNode[];
24
+ } | {
25
+ kind: "each";
26
+ each: () => Iterable<unknown>;
27
+ build: (item: unknown, index: number) => RenderNode[];
28
+ key?: (item: unknown, index: number) => unknown;
29
+ } | {
30
+ kind: "children";
31
+ } | {
32
+ kind: "element";
33
+ tag: string;
34
+ attrs: Record<string, RenderAttr>;
35
+ events: Record<string, (e: Event) => unknown>;
36
+ children: RenderNode[];
37
+ };
38
+ export interface JSlopInstance {
39
+ actions: Record<string, (...args: unknown[]) => unknown>;
40
+ buildView(): RenderNode;
41
+ buildHead?(): RenderNode[];
42
+ serializeState(): Record<string, unknown>;
43
+ restoreState(s: Record<string, unknown>): void;
44
+ children?: JSlopInstance[];
45
+ }
46
+ export interface JSlopComponent {
47
+ name: string;
48
+ create(props?: Record<string, unknown>): JSlopInstance;
49
+ }
50
+ export interface RenderResult {
51
+ html: string;
52
+ /** Rendered HTML for the page <head>, from each component's `head { … }` block. */
53
+ head: string;
54
+ /** Every component name rendered in this tree (used to inject scoped styles). */
55
+ nestedComponents: Set<string>;
56
+ capsule: {
57
+ components: Array<{
58
+ cid: string;
59
+ name: string;
60
+ props: Record<string, unknown>;
61
+ state: Record<string, unknown>;
62
+ }>;
63
+ };
64
+ }
65
+ export declare function renderComponent(component: JSlopComponent, props?: Record<string, unknown>, cid?: string): RenderResult;
66
+ /**
67
+ * Render a route nested inside zero or more layouts. Each layout must contain
68
+ * exactly one `<children/>` placeholder; the inner HTML is substituted in.
69
+ * Capsule entries are merged with unique cids so the client can boot each
70
+ * island independently.
71
+ */
72
+ export declare function renderRouteChain(opts: {
73
+ route: JSlopComponent;
74
+ routeProps?: Record<string, unknown>;
75
+ /** Outermost layout first. Each layout must have a `<children/>`. */
76
+ layouts?: JSlopComponent[];
77
+ /**
78
+ * Props passed to every layout in the chain. Typically the merged result
79
+ * of each layout's `load()`, so a layout can declare `prop user = null`
80
+ * and have it injected by its own loader.
81
+ */
82
+ layoutProps?: Record<string, unknown>;
83
+ }): RenderResult;
84
+ export declare function renderPage(opts: {
85
+ title: string;
86
+ component: JSlopComponent;
87
+ /** Layouts wrapping the route, outermost first. Each must have `<children/>`. */
88
+ layouts?: JSlopComponent[];
89
+ appScriptUrl: string;
90
+ props?: Record<string, unknown>;
91
+ /** Props passed to every layout (typically a merged layout-load result). */
92
+ layoutProps?: Record<string, unknown>;
93
+ stylesheets?: string[];
94
+ head?: string;
95
+ }): string;
package/dist/index.js ADDED
@@ -0,0 +1,359 @@
1
+ import { getRegisteredStyle } from "@jslop/runtime";
2
+ const VOID_ELEMENTS = new Set([
3
+ "area", "base", "br", "col", "embed", "hr", "img", "input",
4
+ "link", "meta", "param", "source", "track", "wbr",
5
+ ]);
6
+ const CHILDREN_PLACEHOLDER = "<jslop-children></jslop-children>";
7
+ // HTML boolean attributes: presence implies true, absence implies false.
8
+ const BOOLEAN_ATTRS = new Set([
9
+ "checked", "disabled", "readonly", "required", "selected", "multiple",
10
+ "hidden", "autofocus", "autoplay", "controls", "loop", "muted",
11
+ "open", "reversed", "default",
12
+ ]);
13
+ // Attributes whose values are URLs. Values rendered into these attributes are
14
+ // passed through `safeUrl()` so that `javascript:` / `data:` / `vbscript:` and
15
+ // other script-bearing schemes can never reach the browser's URL parser. The
16
+ // list is the set of standard URL-bearing HTML attributes; if a future feature
17
+ // introduces a new URL attribute, add it here.
18
+ const URL_ATTRS = new Set([
19
+ "href", "src", "action", "formaction", "poster", "data",
20
+ "background", "cite", "longdesc", "manifest", "ping", "srcdoc",
21
+ "usemap", "icon", "xlink:href",
22
+ ]);
23
+ // Tags forbidden inside head fragments — these are raw-text / script-bearing
24
+ // elements where naïve string escaping is insufficient. Authors who need
25
+ // inline JS/CSS must inject it through opts.head with their own escaping.
26
+ const FORBIDDEN_HEAD_TAGS = new Set([
27
+ "script", "style", "noscript", "iframe", "object", "embed",
28
+ ]);
29
+ // HTML attribute names must match this pattern. Used as a defense-in-depth
30
+ // guard against any future codepath that lets a template/spread produce an
31
+ // arbitrary attribute name. Permissive enough to cover real attributes
32
+ // (`data-*`, `aria-*`, `xlink:href`) but rejects whitespace, quotes, `=`, `/`,
33
+ // `>`, etc., that would let a name break out of the attribute syntax.
34
+ const SAFE_ATTR_NAME = /^[A-Za-z_:][A-Za-z0-9_:.\-]*$/;
35
+ function isSafeAttrName(name) {
36
+ return SAFE_ATTR_NAME.test(name);
37
+ }
38
+ /**
39
+ * Filter a URL destined for an HTML URL attribute (href/src/action/…). Any
40
+ * scheme that isn't a known-safe data scheme is replaced with `about:blank`
41
+ * so that an attacker-controlled value cannot execute script via
42
+ * `javascript:`, `vbscript:`, `data:text/html`, etc.
43
+ *
44
+ * Allowed:
45
+ * - Relative URLs (no scheme), including protocol-relative `//host/…`,
46
+ * fragment-only `#x`, query-only `?x`, absolute paths `/x`.
47
+ * - http: / https: / mailto: / tel: / ftp: / sms:
48
+ * - data:image/* (common safe use case for inline images/favicons).
49
+ * Everything else (including any `javascript:` form, leading whitespace
50
+ * tricks, control-character smuggling) is neutralized.
51
+ */
52
+ function safeUrl(input) {
53
+ // Strip control characters (\x00-\x1F and \x7F) which browsers historically
54
+ // tolerate inside the scheme and which can be used to disguise `javascript:`
55
+ // as `java\tscript:` etc. Then trim surrounding whitespace.
56
+ // eslint-disable-next-line no-control-regex
57
+ const cleaned = input.replace(/[\x00-\x1F\x7F]/g, "").trim();
58
+ if (cleaned === "")
59
+ return "";
60
+ // Relative URL: no scheme. The first character is not an ASCII letter, or
61
+ // there is no `:` before the first `/`, `?`, or `#`.
62
+ const schemeMatch = /^([A-Za-z][A-Za-z0-9+.\-]*):/.exec(cleaned);
63
+ if (!schemeMatch)
64
+ return cleaned;
65
+ const scheme = schemeMatch[1].toLowerCase();
66
+ if (scheme === "http" || scheme === "https" || scheme === "mailto" ||
67
+ scheme === "tel" || scheme === "ftp" || scheme === "sms") {
68
+ return cleaned;
69
+ }
70
+ if (scheme === "data") {
71
+ // Only allow image data: URLs (common for favicons / inline thumbnails).
72
+ // Block `data:text/html`, `data:application/*`, etc., which can execute
73
+ // script via top-level navigation or iframe srcdoc-like contexts.
74
+ if (/^data:image\/(png|jpe?g|gif|webp|avif|svg\+xml|x-icon|vnd\.microsoft\.icon)[;,]/i.test(cleaned)) {
75
+ // SVG can contain script — refuse svg+xml unless explicitly base64-encoded
76
+ // and even then it's risky in some contexts, but base64-svg via <img>
77
+ // is generally safe. We allow it; authors using it in <object>/<iframe>
78
+ // are accepting the risk.
79
+ return cleaned;
80
+ }
81
+ return "about:blank";
82
+ }
83
+ return "about:blank";
84
+ }
85
+ export function renderComponent(component, props = {}, cid = "c0") {
86
+ const instance = component.create(props);
87
+ const view = instance.buildView();
88
+ if (view.kind !== "element") {
89
+ throw new Error(`component ${component.name}: root view must be an element`);
90
+ }
91
+ // Track every nested component name encountered while rendering this tree
92
+ // so renderPage can emit a <style> tag for each unique name. Without this,
93
+ // a route's <PresetCard/>s in an each block would inherit no styles.
94
+ const nestedComponents = new Set([component.name]);
95
+ const html = renderElement(view, { cid, componentName: component.name }, nestedComponents);
96
+ const head = renderHeadNodes(instance.buildHead?.() ?? []);
97
+ return {
98
+ html,
99
+ head,
100
+ nestedComponents,
101
+ capsule: {
102
+ components: [{ cid, name: component.name, props, state: instance.serializeState() }],
103
+ },
104
+ };
105
+ }
106
+ function renderHeadNodes(nodes) {
107
+ return nodes.map((n) => renderHeadNode(n)).join("");
108
+ }
109
+ /**
110
+ * Render a head fragment node WITHOUT the <jslop-b> bind wrapper that the body
111
+ * renderer emits — head text bindings (e.g. inside <title>) must produce raw
112
+ * text so the browser sees a clean tag. Head is server-only anyway; there is
113
+ * no client-side reactivity to hydrate against.
114
+ */
115
+ function renderHeadNode(node) {
116
+ if (node.kind === "text")
117
+ return escapeHtml(node.value);
118
+ if (node.kind === "bind")
119
+ return escapeHtml(node.get());
120
+ if (node.kind === "element") {
121
+ // Raw-text / script-bearing elements need context-specific escaping
122
+ // that plain HTML escaping doesn't provide. Forbid them in head fragments;
123
+ // authors who need them can inject via opts.head with their own escaping.
124
+ if (FORBIDDEN_HEAD_TAGS.has(node.tag.toLowerCase())) {
125
+ throw new Error(`head fragments may not contain <${node.tag}> — inject it via opts.head with explicit escaping`);
126
+ }
127
+ const attrParts = [];
128
+ for (const [k, v] of Object.entries(node.attrs)) {
129
+ if (!isSafeAttrName(k))
130
+ continue;
131
+ const isUrl = URL_ATTRS.has(k.toLowerCase());
132
+ const filter = (raw) => escapeAttr(isUrl ? safeUrl(raw) : raw);
133
+ if (typeof v === "string")
134
+ attrParts.push(`${k}="${filter(v)}"`);
135
+ else if (v.kind === "bind")
136
+ attrParts.push(`${k}="${filter(v.get())}"`);
137
+ else if (v.kind === "prop")
138
+ attrParts.push(`${k}="${filter(String(v.get() ?? ""))}"`);
139
+ }
140
+ const open = `<${node.tag}${attrParts.length ? " " + attrParts.join(" ") : ""}>`;
141
+ if (VOID_ELEMENTS.has(node.tag))
142
+ return open;
143
+ const inner = node.children.map(renderHeadNode).join("");
144
+ return `${open}${inner}</${node.tag}>`;
145
+ }
146
+ throw new Error(`head fragments only support static elements, text, and {expr} — got '${node.kind}'`);
147
+ }
148
+ /**
149
+ * Render a route nested inside zero or more layouts. Each layout must contain
150
+ * exactly one `<children/>` placeholder; the inner HTML is substituted in.
151
+ * Capsule entries are merged with unique cids so the client can boot each
152
+ * island independently.
153
+ */
154
+ export function renderRouteChain(opts) {
155
+ const layouts = opts.layouts ?? [];
156
+ let cidCounter = 0;
157
+ const nextCid = () => `c${cidCounter++}`;
158
+ const routeResult = renderComponent(opts.route, opts.routeProps ?? {}, nextCid());
159
+ let html = routeResult.html;
160
+ const components = [...routeResult.capsule.components];
161
+ const nestedComponents = new Set(routeResult.nestedComponents);
162
+ // Layouts contribute their head first (outermost → innermost), then the
163
+ // route's head — so the route's <title>/meta ends up last in the document
164
+ // head and wins for any duplicate tags the browser de-dupes by position.
165
+ const headParts = [];
166
+ // Wrap innermost-first so each replacement targets the *current* outermost
167
+ // placeholder. The CHILDREN_PLACEHOLDER constant is unique enough that a
168
+ // literal string replace is safe here (we never emit it for user content).
169
+ for (let i = layouts.length - 1; i >= 0; i--) {
170
+ const layout = layouts[i];
171
+ const layoutResult = renderComponent(layout, opts.layoutProps ?? {}, nextCid());
172
+ const idx = layoutResult.html.indexOf(CHILDREN_PLACEHOLDER);
173
+ if (idx === -1) {
174
+ throw new Error(`layout ${layout.name} has no <children/> element — required for routed content`);
175
+ }
176
+ html =
177
+ layoutResult.html.slice(0, idx) +
178
+ html +
179
+ layoutResult.html.slice(idx + CHILDREN_PLACEHOLDER.length);
180
+ components.push(...layoutResult.capsule.components);
181
+ for (const n of layoutResult.nestedComponents)
182
+ nestedComponents.add(n);
183
+ headParts.unshift(layoutResult.head);
184
+ }
185
+ headParts.push(routeResult.head);
186
+ return { html, head: headParts.join(""), nestedComponents, capsule: { components } };
187
+ }
188
+ function renderNode(node, registry) {
189
+ if (node.kind === "text")
190
+ return escapeHtml(node.value);
191
+ if (node.kind === "children")
192
+ return CHILDREN_PLACEHOLDER;
193
+ if (node.kind === "bind") {
194
+ return `<jslop-b>${escapeHtml(node.get())}</jslop-b>`;
195
+ }
196
+ if (node.kind === "if") {
197
+ const active = !!node.test();
198
+ const branch = active ? node.consequent : node.alternate;
199
+ const inner = branch.map((c) => renderNode(c, registry)).join("");
200
+ return `<jslop-if data-jslop-active="${active ? "t" : "f"}">${inner}</jslop-if>`;
201
+ }
202
+ if (node.kind === "each") {
203
+ const source = node.each();
204
+ let i = 0;
205
+ const itemsHtml = [];
206
+ const keyed = typeof node.key === "function";
207
+ for (const item of source) {
208
+ const itemChildren = node.build(item, i);
209
+ const keyAttr = keyed
210
+ ? ` data-jslop-key="${escapeAttr(String(node.key(item, i)))}"`
211
+ : "";
212
+ itemsHtml.push(`<jslop-each-item${keyAttr} style="display:contents">${itemChildren.map((c) => renderNode(c, registry)).join("")}</jslop-each-item>`);
213
+ i++;
214
+ }
215
+ const keyedAttr = keyed ? ` data-jslop-keyed="t"` : "";
216
+ return `<jslop-each data-jslop-count="${i}"${keyedAttr} style="display:contents">${itemsHtml.join("")}</jslop-each>`;
217
+ }
218
+ if (node.kind === "component") {
219
+ if (node.view.kind !== "element") {
220
+ throw new Error(`component ${node.name}: root view must be an element`);
221
+ }
222
+ registry.add(node.name);
223
+ return renderElement(node.view, { componentName: node.name }, registry);
224
+ }
225
+ return renderElement(node, {}, registry);
226
+ }
227
+ function renderElement(node, marker, registry) {
228
+ const attrParts = [];
229
+ for (const [k, v] of Object.entries(node.attrs)) {
230
+ // Reject any attribute name that contains characters which could break
231
+ // out of the `name="value"` syntax. The compiler today only emits valid
232
+ // identifiers, but this is defense-in-depth against future spread/
233
+ // computed-attribute features.
234
+ if (!isSafeAttrName(k))
235
+ continue;
236
+ const isUrl = URL_ATTRS.has(k.toLowerCase());
237
+ const filter = (raw) => escapeAttr(isUrl ? safeUrl(raw) : raw);
238
+ if (typeof v === "string") {
239
+ attrParts.push(`${k}="${filter(v)}"`);
240
+ }
241
+ else if (v.kind === "bind") {
242
+ const val = v.get();
243
+ attrParts.push(`${k}="${filter(val)}" data-jslop-attr-${k}=""`);
244
+ }
245
+ else {
246
+ // kind: "prop" — boolean attributes render presence-based, others
247
+ // stringify their value into the attribute.
248
+ const val = v.get();
249
+ if (BOOLEAN_ATTRS.has(k)) {
250
+ if (val)
251
+ attrParts.push(`${k}="" data-jslop-prop-${k}=""`);
252
+ }
253
+ else {
254
+ attrParts.push(`${k}="${filter(String(val ?? ""))}" data-jslop-prop-${k}=""`);
255
+ }
256
+ }
257
+ }
258
+ for (const evt of Object.keys(node.events)) {
259
+ // Event names are emitted into the attribute *name* position
260
+ // (`data-jslop-on-<evt>`), so they must be strictly validated. Only
261
+ // lowercase alphanumeric plus the `:` namespace separator used by
262
+ // bind:value etc. is allowed.
263
+ if (!/^[a-z][a-z0-9]*(?::[a-z0-9]+)*$/.test(evt))
264
+ continue;
265
+ attrParts.push(`data-jslop-on-${evt}=""`);
266
+ }
267
+ if (marker.cid) {
268
+ attrParts.push(`data-jslop-cid="${escapeAttr(marker.cid)}"`);
269
+ }
270
+ if (marker.componentName) {
271
+ attrParts.push(`data-jslop-component="${escapeAttr(marker.componentName)}"`);
272
+ }
273
+ const open = `<${node.tag}${attrParts.length ? " " + attrParts.join(" ") : ""}>`;
274
+ if (VOID_ELEMENTS.has(node.tag))
275
+ return open;
276
+ const inner = node.children.map((c) => renderNode(c, registry)).join("");
277
+ return `${open}${inner}</${node.tag}>`;
278
+ }
279
+ export function renderPage(opts) {
280
+ const { html, head: componentHead, nestedComponents, capsule } = opts.layouts && opts.layouts.length > 0
281
+ ? renderRouteChain({
282
+ route: opts.component,
283
+ routeProps: opts.props ?? {},
284
+ layouts: opts.layouts,
285
+ layoutProps: opts.layoutProps ?? {},
286
+ })
287
+ : renderComponent(opts.component, opts.props ?? {});
288
+ const capsuleJson = serializeForScript(capsule);
289
+ const linkTags = (opts.stylesheets ?? [])
290
+ .map((href) => `<link rel="stylesheet" href="${escapeAttr(safeUrl(href))}">`)
291
+ .join("");
292
+ const appScriptUrl = escapeAttr(safeUrl(opts.appScriptUrl));
293
+ const extraHead = opts.head ?? "";
294
+ // If the component emitted its own <title>, use it as the document title and
295
+ // suppress the fallback (browsers honor the *last* <title>, but emitting two
296
+ // is sloppy). Search the rendered head for a <title>…</title> tag.
297
+ const titleMatch = /<title[^>]*>([\s\S]*?)<\/title>/.exec(componentHead);
298
+ const fallbackTitle = titleMatch ? "" : `<title>${escapeHtml(opts.title)}</title>\n`;
299
+ // Collect one <style> per unique component name rendered on this page. The
300
+ // capsule lists every mounted component in order; dedup by name so a list of
301
+ // 100 <Card/>s only emits the Card style once.
302
+ const styleTags = [];
303
+ const emittedStyleScopes = new Set();
304
+ for (const name of nestedComponents) {
305
+ const reg = getRegisteredStyle(name);
306
+ if (!reg || emittedStyleScopes.has(reg.scope))
307
+ continue;
308
+ emittedStyleScopes.add(reg.scope);
309
+ styleTags.push(`<style data-jslop-style="${escapeAttr(reg.scope)}">${reg.css}</style>`);
310
+ }
311
+ const componentStyles = styleTags.join("");
312
+ return `<!doctype html>
313
+ <html lang="en">
314
+ <head>
315
+ <meta charset="utf-8">
316
+ <meta name="viewport" content="width=device-width,initial-scale=1">
317
+ ${fallbackTitle}${linkTags}${componentStyles}${componentHead}${extraHead}</head>
318
+ <body>
319
+ <div id="app">${html}</div>
320
+ <script type="application/jslop+json" id="__jslop_capsule">${capsuleJson}</script>
321
+ <script type="module" src="${appScriptUrl}"></script>
322
+ </body>
323
+ </html>`;
324
+ }
325
+ function escapeHtml(s) {
326
+ return s
327
+ .replace(/&/g, "&amp;")
328
+ .replace(/</g, "&lt;")
329
+ .replace(/>/g, "&gt;");
330
+ }
331
+ function escapeAttr(s) {
332
+ return s
333
+ .replace(/&/g, "&amp;")
334
+ .replace(/"/g, "&quot;")
335
+ .replace(/'/g, "&#39;")
336
+ .replace(/</g, "&lt;")
337
+ .replace(/>/g, "&gt;");
338
+ }
339
+ /**
340
+ * Serialize a value for embedding inside a `<script>` tag. Escapes:
341
+ * - `<` → < so `</script>` cannot break out of the script element.
342
+ * - `>` → > for symmetry / belt-and-braces against parser quirks.
343
+ * - `&` → & so HTML entity decoding in attribute-like contexts is inert.
344
+ * - U+2028 / U+2029 → / so the JSON remains a valid JS string
345
+ * literal if the embedding context is ever changed to `text/javascript`.
346
+ *
347
+ * The capsule is embedded in `<script type="application/jslop+json">` today,
348
+ * which browsers treat as inert data — but this serializer is also safe for
349
+ * future call sites that embed JSON into JS contexts directly.
350
+ */
351
+ function serializeForScript(value) {
352
+ return JSON.stringify(value)
353
+ .replace(/</g, "\\u003c")
354
+ .replace(/>/g, "\\u003e")
355
+ .replace(/&/g, "\\u0026")
356
+ .replace(/\u2028/g, "\\u2028")
357
+ .replace(/\u2029/g, "\\u2029");
358
+ }
359
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAyDpD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO;IAC1D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK;CAClD,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,mCAAmC,CAAC;AAEjE,yEAAyE;AACzE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IACrE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO;IAC9D,MAAM,EAAE,UAAU,EAAE,SAAS;CAC9B,CAAC,CAAC;AAEH,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,+CAA+C;AAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM;IACvD,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ;IAC9D,QAAQ,EAAE,MAAM,EAAE,YAAY;CAC/B,CAAC,CAAC;AAEH,6EAA6E;AAC7E,yEAAyE;AACzE,0EAA0E;AAC1E,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;CAC3D,CAAC,CAAC;AAEH,2EAA2E;AAC3E,2EAA2E;AAC3E,uEAAuE;AACvE,+EAA+E;AAC/E,sEAAsE;AACtE,MAAM,cAAc,GAAG,+BAA+B,CAAC;AAEvD,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,OAAO,CAAC,KAAa;IAC5B,4EAA4E;IAC5E,6EAA6E;IAC7E,4DAA4D;IAC5D,4CAA4C;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7D,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAC9B,0EAA0E;IAC1E,qDAAqD;IACrD,MAAM,WAAW,GAAG,8BAA8B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,IAAI,CAAC,WAAW;QAAE,OAAO,OAAO,CAAC;IACjC,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC;IAC7C,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,QAAQ;QAC9D,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7D,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,yEAAyE;QACzE,wEAAwE;QACxE,kEAAkE;QAClE,IAAI,kFAAkF,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACrG,2EAA2E;YAC3E,sEAAsE;YACtE,wEAAwE;YACxE,0BAA0B;YAC1B,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAAyB,EACzB,QAAiC,EAAE,EACnC,GAAG,GAAG,IAAI;IAEV,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;IAClC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,aAAa,SAAS,CAAC,IAAI,gCAAgC,CAAC,CAAC;IAC/E,CAAC;IACD,0EAA0E;IAC1E,2EAA2E;IAC3E,qEAAqE;IACrE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAC3F,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,gBAAgB;QAChB,OAAO,EAAE;YACP,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;SACrF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAmB;IAC1C,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,IAAgB;IACtC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,oEAAoE;QACpE,2EAA2E;QAC3E,0EAA0E;QAC1E,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CACb,mCAAmC,IAAI,CAAC,GAAG,oDAAoD,CAChG,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;gBAAE,SAAS;YACjC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACvE,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;iBAC5D,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;gBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;iBACnE,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;gBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QACjF,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzD,OAAO,GAAG,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC;IACzC,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,wEAAwE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;AACxG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAWhC;IACC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;IACnC,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,OAAO,GAAG,GAAW,EAAE,CAAC,IAAI,UAAU,EAAE,EAAE,CAAC;IAEjD,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAClF,IAAI,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC;IAC5B,MAAM,UAAU,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC/D,wEAAwE;IACxE,0EAA0E;IAC1E,yEAAyE;IACzE,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAChF,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAC5D,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,UAAU,MAAM,CAAC,IAAI,2DAA2D,CACjF,CAAC;QACJ,CAAC;QACD,IAAI;YACF,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBAC/B,IAAI;gBACJ,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAC7D,UAAU,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACpD,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,gBAAgB;YAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACvE,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC;AACvF,CAAC;AAOD,SAAS,UAAU,CAAC,IAAgB,EAAE,QAAqB;IACzD,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,oBAAoB,CAAC;IAC1D,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,YAAY,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;IACxD,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;QACzD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClE,OAAO,gCAAgC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,aAAa,CAAC;IACnF,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,UAAU,CAAC;QAC7C,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,KAAK;gBACnB,CAAC,CAAC,oBAAoB,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;gBAC/D,CAAC,CAAC,EAAE,CAAC;YACP,SAAS,CAAC,IAAI,CACZ,mBAAmB,OAAO,6BAA6B,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,oBAAoB,CACrI,CAAC;YACF,CAAC,EAAE,CAAC;QACN,CAAC;QACD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,iCAAiC,CAAC,IAAI,SAAS,6BAA6B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC;IACvH,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,IAAI,gCAAgC,CAAC,CAAC;QAC1E,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,aAAa,CACpB,IAA8C,EAC9C,MAAgB,EAChB,QAAqB;IAErB,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,uEAAuE;QACvE,wEAAwE;QACxE,mEAAmE;QACnE,+BAA+B;QAC/B,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;YAAE,SAAS;QACjC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACvE,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACpB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,kEAAkE;YAClE,4CAA4C;YAC5C,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACpB,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzB,IAAI,GAAG;oBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;YAC7D,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3C,6DAA6D;QAC7D,oEAAoE;QACpE,kEAAkE;QAClE,8BAA8B;QAC9B,IAAI,CAAC,iCAAiC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3D,SAAS,CAAC,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,SAAS,CAAC,IAAI,CAAC,mBAAmB,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzB,SAAS,CAAC,IAAI,CAAC,yBAAyB,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC/E,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;IACjF,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzE,OAAO,GAAG,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAW1B;IACC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAC5D,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QACrC,CAAC,CAAC,gBAAgB,CAAC;YACf,KAAK,EAAE,IAAI,CAAC,SAAS;YACrB,UAAU,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;YAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;SACpC,CAAC;QACJ,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;SACtC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gCAAgC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;SAC5E,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAClC,6EAA6E;IAC7E,6EAA6E;IAC7E,mEAAmE;IACnE,MAAM,UAAU,GAAG,iCAAiC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;IACrF,2EAA2E;IAC3E,6EAA6E;IAC7E,+CAA+C;IAC/C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QACxD,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC,4BAA4B,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3C,OAAO;;;;;EAKP,aAAa,GAAG,QAAQ,GAAG,eAAe,GAAG,aAAa,GAAG,SAAS;;gBAExD,IAAI;6DACyC,WAAW;6BAC3C,YAAY;;QAEjC,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SACzB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;SACxB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;SACxB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;SACxB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC;SAC7B,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACnC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@jslop/server",
3
+ "version": "0.1.0",
4
+ "description": "Server-side renderer for JSlop. Renders components to HTML and emits a serialized state capsule that @jslop/client consumes on hydration.",
5
+ "keywords": [
6
+ "jslop",
7
+ "ssr",
8
+ "server",
9
+ "framework"
10
+ ],
11
+ "license": "MIT",
12
+ "author": "p-arndt",
13
+ "homepage": "https://github.com/p-arndt/jslop#readme",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/p-arndt/jslop.git",
17
+ "directory": "packages/server"
18
+ },
19
+ "bugs": "https://github.com/p-arndt/jslop/issues",
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "dependencies": {
40
+ "@jslop/runtime": "^0.1.0"
41
+ },
42
+ "devDependencies": {
43
+ "typescript": "^5.6.3"
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -p tsconfig.json"
47
+ }
48
+ }