@c9up/aurora 0.1.33 → 0.1.34
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/dist/liveClient.js +8 -1
- package/dist/ssr.js +25 -10
- package/package.json +4 -4
- package/src/liveClient.ts +13 -1
- package/src/ssr.ts +25 -10
package/dist/liveClient.js
CHANGED
|
@@ -76,7 +76,14 @@ export function buildLiveTransport(relayClient, http, options = {}) {
|
|
|
76
76
|
return {
|
|
77
77
|
subscribe: (channel, handler) => relayClient.subscribe(channel, handler),
|
|
78
78
|
post: (id, event, payload) => {
|
|
79
|
-
|
|
79
|
+
// A post that fails means the server never saw this interaction, so
|
|
80
|
+
// the component's server-side state and what the user is looking at
|
|
81
|
+
// have diverged — silence is the worst possible answer. Unhandled,
|
|
82
|
+
// it was also a bare `Uncaught (in promise)` with no clue which
|
|
83
|
+
// event was lost.
|
|
84
|
+
void (async () => http.post(path, { id, event, payload }))().catch((err) => {
|
|
85
|
+
console.warn(`[aurora/live] '${event}' on ${id} did not reach the server; this component is now out of sync:`, err);
|
|
86
|
+
});
|
|
80
87
|
},
|
|
81
88
|
};
|
|
82
89
|
}
|
package/dist/ssr.js
CHANGED
|
@@ -45,19 +45,34 @@ function stringifyTemplateResult(result) {
|
|
|
45
45
|
// the matching value, and consume the closing `"` from the next
|
|
46
46
|
// segment. This three-step coordination is why the loop holds a
|
|
47
47
|
// `pendingClosingQuote` flag.
|
|
48
|
-
|
|
48
|
+
// Which quote closes the directive currently being skipped, so the closing
|
|
49
|
+
// one consumed is the one that was opened. Undefined when none is pending.
|
|
50
|
+
let pendingClosingQuote;
|
|
49
51
|
const scanner = new TagScanner();
|
|
50
52
|
for (let i = 0; i < strings.length; i++) {
|
|
51
53
|
let segment = strings[i];
|
|
52
|
-
if (pendingClosingQuote) {
|
|
53
|
-
segment =
|
|
54
|
-
|
|
54
|
+
if (pendingClosingQuote !== undefined) {
|
|
55
|
+
segment =
|
|
56
|
+
pendingClosingQuote === '"'
|
|
57
|
+
? segment.replace(/^"/, "")
|
|
58
|
+
: segment.replace(/^'/, "");
|
|
59
|
+
pendingClosingQuote = undefined;
|
|
55
60
|
}
|
|
56
|
-
|
|
61
|
+
// Both quote styles. Matching only `="` left `@click='${handler}'`
|
|
62
|
+
// unrecognised, so the handler fell through to `stringifyValue`, which
|
|
63
|
+
// CALLED it — a client event handler running on the server, its return
|
|
64
|
+
// value written into the HTML, and any exception swallowed.
|
|
65
|
+
const directiveMatch = segment.match(/\s([@?.][\w-]+)=("|'|)$/);
|
|
57
66
|
const skipValue = directiveMatch !== null;
|
|
58
67
|
if (directiveMatch) {
|
|
59
68
|
segment = segment.slice(0, segment.length - directiveMatch[0].length);
|
|
60
|
-
|
|
69
|
+
// Only a quoted directive leaves a closing quote to swallow.
|
|
70
|
+
pendingClosingQuote =
|
|
71
|
+
directiveMatch[2] === '"'
|
|
72
|
+
? '"'
|
|
73
|
+
: directiveMatch[2] === "'"
|
|
74
|
+
? "'"
|
|
75
|
+
: undefined;
|
|
61
76
|
}
|
|
62
77
|
out += segment;
|
|
63
78
|
scanner.consume(segment);
|
|
@@ -147,10 +162,10 @@ function stringifyValue(value, inAttribute) {
|
|
|
147
162
|
if (isSignal(value))
|
|
148
163
|
return stringifyValue(value(), inAttribute);
|
|
149
164
|
if (typeof value === "function") {
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
165
|
+
// A function here is a reactive expression — `class="${() => …}"` in an
|
|
166
|
+
// attribute, `${() => …}` in text — and is evaluated eagerly
|
|
167
|
+
// server-side. Directive values (`@click`, `?disabled`, `.prop`) never
|
|
168
|
+
// reach this point: the scanner skips them, whatever quoting they use.
|
|
154
169
|
try {
|
|
155
170
|
return stringifyValue(value(), inAttribute);
|
|
156
171
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c9up/aurora",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"description": "Aurora — reactive UI runtime for the Ream framework. Tagged-template DOM, signal-based state, isomorphic SSR + hydration, zero build step.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
"@biomejs/biome": "^2.4.10",
|
|
57
57
|
"@c9up/comet": "^0.1.0",
|
|
58
58
|
"@types/node": "^22.19.15",
|
|
59
|
-
"@vitest/browser": "4.1.
|
|
60
|
-
"@vitest/browser-playwright": "4.1.
|
|
61
|
-
"happy-dom": "^
|
|
59
|
+
"@vitest/browser": "4.1.11",
|
|
60
|
+
"@vitest/browser-playwright": "4.1.11",
|
|
61
|
+
"happy-dom": "^20.12.0",
|
|
62
62
|
"playwright": "^1.61.1",
|
|
63
63
|
"typescript": "^6.0.2",
|
|
64
64
|
"vitest": "4.1.9"
|
package/src/liveClient.ts
CHANGED
|
@@ -118,7 +118,19 @@ export function buildLiveTransport(
|
|
|
118
118
|
subscribe: (channel, handler) =>
|
|
119
119
|
relayClient.subscribe<SlotPatch[]>(channel, handler),
|
|
120
120
|
post: (id, event, payload) => {
|
|
121
|
-
|
|
121
|
+
// A post that fails means the server never saw this interaction, so
|
|
122
|
+
// the component's server-side state and what the user is looking at
|
|
123
|
+
// have diverged — silence is the worst possible answer. Unhandled,
|
|
124
|
+
// it was also a bare `Uncaught (in promise)` with no clue which
|
|
125
|
+
// event was lost.
|
|
126
|
+
void (async () => http.post(path, { id, event, payload }))().catch(
|
|
127
|
+
(err: unknown) => {
|
|
128
|
+
console.warn(
|
|
129
|
+
`[aurora/live] '${event}' on ${id} did not reach the server; this component is now out of sync:`,
|
|
130
|
+
err,
|
|
131
|
+
);
|
|
132
|
+
},
|
|
133
|
+
);
|
|
122
134
|
},
|
|
123
135
|
};
|
|
124
136
|
}
|
package/src/ssr.ts
CHANGED
|
@@ -49,19 +49,34 @@ function stringifyTemplateResult(result: TemplateResult): string {
|
|
|
49
49
|
// the matching value, and consume the closing `"` from the next
|
|
50
50
|
// segment. This three-step coordination is why the loop holds a
|
|
51
51
|
// `pendingClosingQuote` flag.
|
|
52
|
-
|
|
52
|
+
// Which quote closes the directive currently being skipped, so the closing
|
|
53
|
+
// one consumed is the one that was opened. Undefined when none is pending.
|
|
54
|
+
let pendingClosingQuote: '"' | "'" | undefined;
|
|
53
55
|
const scanner = new TagScanner();
|
|
54
56
|
for (let i = 0; i < strings.length; i++) {
|
|
55
57
|
let segment = strings[i];
|
|
56
|
-
if (pendingClosingQuote) {
|
|
57
|
-
segment =
|
|
58
|
-
|
|
58
|
+
if (pendingClosingQuote !== undefined) {
|
|
59
|
+
segment =
|
|
60
|
+
pendingClosingQuote === '"'
|
|
61
|
+
? segment.replace(/^"/, "")
|
|
62
|
+
: segment.replace(/^'/, "");
|
|
63
|
+
pendingClosingQuote = undefined;
|
|
59
64
|
}
|
|
60
|
-
|
|
65
|
+
// Both quote styles. Matching only `="` left `@click='${handler}'`
|
|
66
|
+
// unrecognised, so the handler fell through to `stringifyValue`, which
|
|
67
|
+
// CALLED it — a client event handler running on the server, its return
|
|
68
|
+
// value written into the HTML, and any exception swallowed.
|
|
69
|
+
const directiveMatch = segment.match(/\s([@?.][\w-]+)=("|'|)$/);
|
|
61
70
|
const skipValue = directiveMatch !== null;
|
|
62
71
|
if (directiveMatch) {
|
|
63
72
|
segment = segment.slice(0, segment.length - directiveMatch[0].length);
|
|
64
|
-
|
|
73
|
+
// Only a quoted directive leaves a closing quote to swallow.
|
|
74
|
+
pendingClosingQuote =
|
|
75
|
+
directiveMatch[2] === '"'
|
|
76
|
+
? '"'
|
|
77
|
+
: directiveMatch[2] === "'"
|
|
78
|
+
? "'"
|
|
79
|
+
: undefined;
|
|
65
80
|
}
|
|
66
81
|
out += segment;
|
|
67
82
|
scanner.consume(segment);
|
|
@@ -148,10 +163,10 @@ function stringifyValue(value: unknown, inAttribute: boolean): string {
|
|
|
148
163
|
if (value === true) return inAttribute ? "" : "true";
|
|
149
164
|
if (isSignal(value)) return stringifyValue(value(), inAttribute);
|
|
150
165
|
if (typeof value === "function") {
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
//
|
|
166
|
+
// A function here is a reactive expression — `class="${() => …}"` in an
|
|
167
|
+
// attribute, `${() => …}` in text — and is evaluated eagerly
|
|
168
|
+
// server-side. Directive values (`@click`, `?disabled`, `.prop`) never
|
|
169
|
+
// reach this point: the scanner skips them, whatever quoting they use.
|
|
155
170
|
try {
|
|
156
171
|
return stringifyValue((value as () => unknown)(), inAttribute);
|
|
157
172
|
} catch {
|