@c9up/aurora 0.1.4 → 0.1.5
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/browser.d.ts +28 -0
- package/dist/browser.js +69 -0
- package/dist/hydrate.js +11 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.js +7 -5
- package/dist/server.d.ts +4 -0
- package/dist/server.js +10 -0
- package/dist/ssr.js +11 -1
- package/package.json +5 -1
- package/src/browser.ts +68 -0
- package/src/hydrate.ts +15 -1
- package/src/index.ts +7 -20
- package/src/server.ts +22 -0
- package/src/ssr.ts +10 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser DX helpers — navigation + a typed `localStorage` wrapper.
|
|
3
|
+
*
|
|
4
|
+
* All are SSR-safe: on the server (no `window` / `localStorage`) navigation is
|
|
5
|
+
* a no-op and storage reads return `null`, so the same code runs during SSR
|
|
6
|
+
* without `typeof window` guards at every call site. Node-free — part of the
|
|
7
|
+
* client barrel.
|
|
8
|
+
*/
|
|
9
|
+
/** Navigate to `url` with a full page load. No-op during SSR. */
|
|
10
|
+
export declare function redirect(url: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Navigate to `url`, replacing the current history entry (no back-button trap —
|
|
13
|
+
* use after a login/logout so "back" doesn't return to the form). No-op on SSR.
|
|
14
|
+
*/
|
|
15
|
+
export declare function replace(url: string): void;
|
|
16
|
+
/** Reload the current page. No-op during SSR. */
|
|
17
|
+
export declare function reload(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Typed, SSR-safe `localStorage` wrapper. Values are JSON-serialised; reads
|
|
20
|
+
* return `null` on the server, on a missing key, or on malformed JSON. Writes
|
|
21
|
+
* swallow quota / private-mode errors so a full storage never crashes the app.
|
|
22
|
+
*/
|
|
23
|
+
export declare const storage: {
|
|
24
|
+
get<T>(key: string): T | null;
|
|
25
|
+
set(key: string, value: unknown): void;
|
|
26
|
+
remove(key: string): void;
|
|
27
|
+
clear(): void;
|
|
28
|
+
};
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser DX helpers — navigation + a typed `localStorage` wrapper.
|
|
3
|
+
*
|
|
4
|
+
* All are SSR-safe: on the server (no `window` / `localStorage`) navigation is
|
|
5
|
+
* a no-op and storage reads return `null`, so the same code runs during SSR
|
|
6
|
+
* without `typeof window` guards at every call site. Node-free — part of the
|
|
7
|
+
* client barrel.
|
|
8
|
+
*/
|
|
9
|
+
/** Navigate to `url` with a full page load. No-op during SSR. */
|
|
10
|
+
export function redirect(url) {
|
|
11
|
+
if (typeof window !== "undefined") {
|
|
12
|
+
window.location.href = url;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Navigate to `url`, replacing the current history entry (no back-button trap —
|
|
17
|
+
* use after a login/logout so "back" doesn't return to the form). No-op on SSR.
|
|
18
|
+
*/
|
|
19
|
+
export function replace(url) {
|
|
20
|
+
if (typeof window !== "undefined") {
|
|
21
|
+
window.location.replace(url);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Reload the current page. No-op during SSR. */
|
|
25
|
+
export function reload() {
|
|
26
|
+
if (typeof window !== "undefined") {
|
|
27
|
+
window.location.reload();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Typed, SSR-safe `localStorage` wrapper. Values are JSON-serialised; reads
|
|
32
|
+
* return `null` on the server, on a missing key, or on malformed JSON. Writes
|
|
33
|
+
* swallow quota / private-mode errors so a full storage never crashes the app.
|
|
34
|
+
*/
|
|
35
|
+
export const storage = {
|
|
36
|
+
get(key) {
|
|
37
|
+
if (typeof localStorage === "undefined")
|
|
38
|
+
return null;
|
|
39
|
+
const raw = localStorage.getItem(key);
|
|
40
|
+
if (raw === null)
|
|
41
|
+
return null;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
set(key, value) {
|
|
50
|
+
if (typeof localStorage === "undefined")
|
|
51
|
+
return;
|
|
52
|
+
try {
|
|
53
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// QuotaExceededError / Safari private mode — best-effort write.
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
remove(key) {
|
|
60
|
+
if (typeof localStorage !== "undefined") {
|
|
61
|
+
localStorage.removeItem(key);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
clear() {
|
|
65
|
+
if (typeof localStorage !== "undefined") {
|
|
66
|
+
localStorage.clear();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
package/dist/hydrate.js
CHANGED
|
@@ -307,11 +307,21 @@ function hydrateTextSlot(commentMarker, value, cleanups, mountHooks, markerCurso
|
|
|
307
307
|
}
|
|
308
308
|
return;
|
|
309
309
|
}
|
|
310
|
-
|
|
310
|
+
let textNode = commentMarker.nodeType === 3 /* TEXT */
|
|
311
311
|
? commentMarker
|
|
312
312
|
: commentMarker.previousSibling?.nodeType === 3
|
|
313
313
|
? commentMarker.previousSibling
|
|
314
314
|
: null;
|
|
315
|
+
if (!textNode &&
|
|
316
|
+
commentMarker.nodeType === 8 /* Comment */ &&
|
|
317
|
+
commentMarker.parentNode) {
|
|
318
|
+
// Empty SSR text slot: a `<!---->` placeholder holds the position
|
|
319
|
+
// (see ssr.ts). Materialize the reactive text node there — node
|
|
320
|
+
// count stays 1, so sibling slot paths remain aligned.
|
|
321
|
+
const fresh = (commentMarker.ownerDocument ?? document).createTextNode("");
|
|
322
|
+
commentMarker.parentNode.replaceChild(fresh, commentMarker);
|
|
323
|
+
textNode = fresh;
|
|
324
|
+
}
|
|
315
325
|
if (!textNode)
|
|
316
326
|
return;
|
|
317
327
|
const dispose = effect(() => {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { redirect, reload, replace, storage } from "./browser.js";
|
|
2
2
|
export { component, onMount, onUnmount } from "./component.js";
|
|
3
3
|
export { html, isTemplateResult } from "./html.js";
|
|
4
4
|
export { hydrate } from "./hydrate.js";
|
|
5
|
-
export { type PageFactory, Pages, type PagesConfig, } from "./Pages.js";
|
|
6
5
|
export { batch, effect, isSignal, memo, onCleanup, type ReadSignal, type Signal, signal, untrack, } from "./reactive.js";
|
|
7
6
|
export { type Disposer, render } from "./render.js";
|
|
8
7
|
export { type AuroraHttpContext, type AuroraResponse, type AuroraRouteConfig, auroraRoute, } from "./route.js";
|
|
9
|
-
export { type RenderHttpContext, type RenderPageOptions, type RenderResponse, renderPage, } from "./server/renderPage.js";
|
|
10
|
-
export { type AssetsHttpContext, type AssetsRequest, type AssetsResponse, type ServeAssetsOptions, serveAssets, } from "./server/serveAssets.js";
|
|
11
8
|
export { renderToString } from "./ssr.js";
|
|
12
9
|
export type { TemplateResult } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
// ───
|
|
2
|
-
|
|
1
|
+
// ─── Client surface (node-free — safe to bundle for the browser) ──────
|
|
2
|
+
//
|
|
3
|
+
// Server-only exports (AuroraManager, Pages, renderPage, serveAssets) that pull
|
|
4
|
+
// node:fs / node:path / node:url live in `@c9up/aurora/server`. Keeping them off
|
|
5
|
+
// this barrel is what lets a browser bundle import the client primitives without
|
|
6
|
+
// the bundler dragging Node built-ins through the import graph.
|
|
7
|
+
export { redirect, reload, replace, storage } from "./browser.js";
|
|
3
8
|
export { component, onMount, onUnmount } from "./component.js";
|
|
4
9
|
export { html, isTemplateResult } from "./html.js";
|
|
5
10
|
export { hydrate } from "./hydrate.js";
|
|
6
|
-
export { Pages, } from "./Pages.js";
|
|
7
11
|
export { batch, effect, isSignal, memo, onCleanup, signal, untrack, } from "./reactive.js";
|
|
8
12
|
export { render } from "./render.js";
|
|
9
13
|
export { auroraRoute, } from "./route.js";
|
|
10
|
-
export { renderPage, } from "./server/renderPage.js";
|
|
11
|
-
export { serveAssets, } from "./server/serveAssets.js";
|
|
12
14
|
export { renderToString } from "./ssr.js";
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AuroraManager, type AuroraManagerConfig } from "./AuroraManager.js";
|
|
2
|
+
export { type PageFactory, Pages, type PagesConfig } from "./Pages.js";
|
|
3
|
+
export { type RenderHttpContext, type RenderPageOptions, type RenderResponse, renderPage, } from "./server/renderPage.js";
|
|
4
|
+
export { type AssetsHttpContext, type AssetsRequest, type AssetsResponse, type ServeAssetsOptions, serveAssets, } from "./server/serveAssets.js";
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// ─── Server-only surface (imports node:fs / node:path / node:url) ─────
|
|
2
|
+
//
|
|
3
|
+
// Kept OUT of the package's main barrel (`@c9up/aurora`) so a browser bundle
|
|
4
|
+
// importing client primitives (component/html/hydrate/render) never pulls the
|
|
5
|
+
// Node built-ins through the import graph. Server code imports from
|
|
6
|
+
// `@c9up/aurora/server`; the client `.` entry stays node-free.
|
|
7
|
+
export { AuroraManager } from "./AuroraManager.js";
|
|
8
|
+
export { Pages } from "./Pages.js";
|
|
9
|
+
export { renderPage, } from "./server/renderPage.js";
|
|
10
|
+
export { serveAssets, } from "./server/serveAssets.js";
|
package/dist/ssr.js
CHANGED
|
@@ -75,8 +75,18 @@ function stringifyTemplateResult(result) {
|
|
|
75
75
|
out += stringifyValue(value, false);
|
|
76
76
|
out += `<!--${SLOT_END}-->`;
|
|
77
77
|
}
|
|
78
|
+
else if (inAttr) {
|
|
79
|
+
out += stringifyValue(value, true);
|
|
80
|
+
}
|
|
78
81
|
else {
|
|
79
|
-
|
|
82
|
+
// Text-region scalar slot. An empty result (e.g. `cond ? x : ''`)
|
|
83
|
+
// would emit NO node and desync the path-based hydration of the
|
|
84
|
+
// following sibling slots (their @input/@submit bindings break).
|
|
85
|
+
// Emit an empty-comment placeholder so the position is preserved
|
|
86
|
+
// — lit-html / Solid do the same; hydration materializes the text
|
|
87
|
+
// node there.
|
|
88
|
+
const text = stringifyValue(value, false);
|
|
89
|
+
out += text === "" ? "<!---->" : text;
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
92
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c9up/aurora",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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",
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
"./hydrate": {
|
|
31
31
|
"types": "./dist/hydrate.d.ts",
|
|
32
32
|
"import": "./dist/hydrate.js"
|
|
33
|
+
},
|
|
34
|
+
"./server": {
|
|
35
|
+
"types": "./dist/server.d.ts",
|
|
36
|
+
"import": "./dist/server.js"
|
|
33
37
|
}
|
|
34
38
|
},
|
|
35
39
|
"peerDependencies": {
|
package/src/browser.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser DX helpers — navigation + a typed `localStorage` wrapper.
|
|
3
|
+
*
|
|
4
|
+
* All are SSR-safe: on the server (no `window` / `localStorage`) navigation is
|
|
5
|
+
* a no-op and storage reads return `null`, so the same code runs during SSR
|
|
6
|
+
* without `typeof window` guards at every call site. Node-free — part of the
|
|
7
|
+
* client barrel.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Navigate to `url` with a full page load. No-op during SSR. */
|
|
11
|
+
export function redirect(url: string): void {
|
|
12
|
+
if (typeof window !== "undefined") {
|
|
13
|
+
window.location.href = url;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Navigate to `url`, replacing the current history entry (no back-button trap —
|
|
19
|
+
* use after a login/logout so "back" doesn't return to the form). No-op on SSR.
|
|
20
|
+
*/
|
|
21
|
+
export function replace(url: string): void {
|
|
22
|
+
if (typeof window !== "undefined") {
|
|
23
|
+
window.location.replace(url);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Reload the current page. No-op during SSR. */
|
|
28
|
+
export function reload(): void {
|
|
29
|
+
if (typeof window !== "undefined") {
|
|
30
|
+
window.location.reload();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Typed, SSR-safe `localStorage` wrapper. Values are JSON-serialised; reads
|
|
36
|
+
* return `null` on the server, on a missing key, or on malformed JSON. Writes
|
|
37
|
+
* swallow quota / private-mode errors so a full storage never crashes the app.
|
|
38
|
+
*/
|
|
39
|
+
export const storage = {
|
|
40
|
+
get<T>(key: string): T | null {
|
|
41
|
+
if (typeof localStorage === "undefined") return null;
|
|
42
|
+
const raw = localStorage.getItem(key);
|
|
43
|
+
if (raw === null) return null;
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
set(key: string, value: unknown): void {
|
|
51
|
+
if (typeof localStorage === "undefined") return;
|
|
52
|
+
try {
|
|
53
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
54
|
+
} catch {
|
|
55
|
+
// QuotaExceededError / Safari private mode — best-effort write.
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
remove(key: string): void {
|
|
59
|
+
if (typeof localStorage !== "undefined") {
|
|
60
|
+
localStorage.removeItem(key);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
clear(): void {
|
|
64
|
+
if (typeof localStorage !== "undefined") {
|
|
65
|
+
localStorage.clear();
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
};
|
package/src/hydrate.ts
CHANGED
|
@@ -422,12 +422,26 @@ function hydrateTextSlot(
|
|
|
422
422
|
}
|
|
423
423
|
return;
|
|
424
424
|
}
|
|
425
|
-
|
|
425
|
+
let textNode =
|
|
426
426
|
commentMarker.nodeType === 3 /* TEXT */
|
|
427
427
|
? (commentMarker as Text)
|
|
428
428
|
: commentMarker.previousSibling?.nodeType === 3
|
|
429
429
|
? (commentMarker.previousSibling as Text)
|
|
430
430
|
: null;
|
|
431
|
+
if (
|
|
432
|
+
!textNode &&
|
|
433
|
+
commentMarker.nodeType === 8 /* Comment */ &&
|
|
434
|
+
commentMarker.parentNode
|
|
435
|
+
) {
|
|
436
|
+
// Empty SSR text slot: a `<!---->` placeholder holds the position
|
|
437
|
+
// (see ssr.ts). Materialize the reactive text node there — node
|
|
438
|
+
// count stays 1, so sibling slot paths remain aligned.
|
|
439
|
+
const fresh = (commentMarker.ownerDocument ?? document).createTextNode(
|
|
440
|
+
"",
|
|
441
|
+
);
|
|
442
|
+
commentMarker.parentNode.replaceChild(fresh, commentMarker);
|
|
443
|
+
textNode = fresh;
|
|
444
|
+
}
|
|
431
445
|
if (!textNode) return;
|
|
432
446
|
const dispose = effect(() => {
|
|
433
447
|
const v = fn();
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
// ───
|
|
2
|
-
|
|
1
|
+
// ─── Client surface (node-free — safe to bundle for the browser) ──────
|
|
2
|
+
//
|
|
3
|
+
// Server-only exports (AuroraManager, Pages, renderPage, serveAssets) that pull
|
|
4
|
+
// node:fs / node:path / node:url live in `@c9up/aurora/server`. Keeping them off
|
|
5
|
+
// this barrel is what lets a browser bundle import the client primitives without
|
|
6
|
+
// the bundler dragging Node built-ins through the import graph.
|
|
7
|
+
export { redirect, reload, replace, storage } from "./browser.js";
|
|
3
8
|
export { component, onMount, onUnmount } from "./component.js";
|
|
4
9
|
export { html, isTemplateResult } from "./html.js";
|
|
5
10
|
export { hydrate } from "./hydrate.js";
|
|
6
|
-
export {
|
|
7
|
-
type PageFactory,
|
|
8
|
-
Pages,
|
|
9
|
-
type PagesConfig,
|
|
10
|
-
} from "./Pages.js";
|
|
11
11
|
export {
|
|
12
12
|
batch,
|
|
13
13
|
effect,
|
|
@@ -26,18 +26,5 @@ export {
|
|
|
26
26
|
type AuroraRouteConfig,
|
|
27
27
|
auroraRoute,
|
|
28
28
|
} from "./route.js";
|
|
29
|
-
export {
|
|
30
|
-
type RenderHttpContext,
|
|
31
|
-
type RenderPageOptions,
|
|
32
|
-
type RenderResponse,
|
|
33
|
-
renderPage,
|
|
34
|
-
} from "./server/renderPage.js";
|
|
35
|
-
export {
|
|
36
|
-
type AssetsHttpContext,
|
|
37
|
-
type AssetsRequest,
|
|
38
|
-
type AssetsResponse,
|
|
39
|
-
type ServeAssetsOptions,
|
|
40
|
-
serveAssets,
|
|
41
|
-
} from "./server/serveAssets.js";
|
|
42
29
|
export { renderToString } from "./ssr.js";
|
|
43
30
|
export type { TemplateResult } from "./types.js";
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ─── Server-only surface (imports node:fs / node:path / node:url) ─────
|
|
2
|
+
//
|
|
3
|
+
// Kept OUT of the package's main barrel (`@c9up/aurora`) so a browser bundle
|
|
4
|
+
// importing client primitives (component/html/hydrate/render) never pulls the
|
|
5
|
+
// Node built-ins through the import graph. Server code imports from
|
|
6
|
+
// `@c9up/aurora/server`; the client `.` entry stays node-free.
|
|
7
|
+
|
|
8
|
+
export { AuroraManager, type AuroraManagerConfig } from "./AuroraManager.js";
|
|
9
|
+
export { type PageFactory, Pages, type PagesConfig } from "./Pages.js";
|
|
10
|
+
export {
|
|
11
|
+
type RenderHttpContext,
|
|
12
|
+
type RenderPageOptions,
|
|
13
|
+
type RenderResponse,
|
|
14
|
+
renderPage,
|
|
15
|
+
} from "./server/renderPage.js";
|
|
16
|
+
export {
|
|
17
|
+
type AssetsHttpContext,
|
|
18
|
+
type AssetsRequest,
|
|
19
|
+
type AssetsResponse,
|
|
20
|
+
type ServeAssetsOptions,
|
|
21
|
+
serveAssets,
|
|
22
|
+
} from "./server/serveAssets.js";
|
package/src/ssr.ts
CHANGED
|
@@ -78,8 +78,17 @@ function stringifyTemplateResult(result: TemplateResult): string {
|
|
|
78
78
|
out += `<!--${SLOT_START}-->`;
|
|
79
79
|
out += stringifyValue(value, false);
|
|
80
80
|
out += `<!--${SLOT_END}-->`;
|
|
81
|
+
} else if (inAttr) {
|
|
82
|
+
out += stringifyValue(value, true);
|
|
81
83
|
} else {
|
|
82
|
-
|
|
84
|
+
// Text-region scalar slot. An empty result (e.g. `cond ? x : ''`)
|
|
85
|
+
// would emit NO node and desync the path-based hydration of the
|
|
86
|
+
// following sibling slots (their @input/@submit bindings break).
|
|
87
|
+
// Emit an empty-comment placeholder so the position is preserved
|
|
88
|
+
// — lit-html / Solid do the same; hydration materializes the text
|
|
89
|
+
// node there.
|
|
90
|
+
const text = stringifyValue(value, false);
|
|
91
|
+
out += text === "" ? "<!---->" : text;
|
|
83
92
|
}
|
|
84
93
|
}
|
|
85
94
|
}
|