@zenithbuild/runtime 0.6.6 → 0.6.9
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/cleanup.d.ts +31 -0
- package/dist/cleanup.js +0 -11
- package/dist/diagnostics.d.ts +4 -0
- package/dist/diagnostics.js +41 -65
- package/dist/effect.d.ts +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.js +1 -11
- package/dist/events.d.ts +8 -0
- package/dist/events.js +2 -6
- package/dist/hydrate.d.ts +57 -0
- package/dist/hydrate.js +110 -351
- package/dist/index.d.ts +6 -0
- package/dist/platform.d.ts +11 -0
- package/dist/platform.js +18 -45
- package/dist/ref.d.ts +4 -0
- package/dist/ref.js +1 -9
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.js +8 -12
- package/dist/signal.d.ts +7 -0
- package/dist/signal.js +3 -15
- package/dist/state.d.ts +10 -0
- package/dist/state.js +4 -20
- package/dist/template.d.ts +2 -0
- package/dist/template.js +0 -10
- package/dist/zeneffect.d.ts +17 -0
- package/dist/zeneffect.js +26 -126
- package/package.json +6 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { signal } from "./signal.js";
|
|
2
|
+
export { state } from "./state.js";
|
|
3
|
+
export { zeneffect } from "./zeneffect.js";
|
|
4
|
+
export { hydrate } from "./hydrate.js";
|
|
5
|
+
export { zenWindow, zenDocument } from "./env.js";
|
|
6
|
+
export { zenOn, zenResize, collectRefs } from "./platform.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ResizeSize = {
|
|
2
|
+
w: number;
|
|
3
|
+
h: number;
|
|
4
|
+
};
|
|
5
|
+
export declare function zenOn(target: EventTarget | null, eventName: string, handler: EventListener, options?: AddEventListenerOptions | boolean): () => void;
|
|
6
|
+
export declare function zenResize(handler: (size: ResizeSize) => void): () => void;
|
|
7
|
+
type RefLike<T extends Element> = {
|
|
8
|
+
current?: T | null;
|
|
9
|
+
} | null | undefined;
|
|
10
|
+
export declare function collectRefs<T extends Element>(...refs: RefLike<T>[]): T[];
|
|
11
|
+
export {};
|
package/dist/platform.js
CHANGED
|
@@ -1,70 +1,51 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// platform.
|
|
2
|
+
// platform.ts — Zenith Runtime canonical DOM/platform helpers
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// zenOn: SSR-safe event subscription with disposer
|
|
5
5
|
// zenResize: window resize handler with rAF throttle
|
|
6
6
|
// collectRefs: deterministic null-filtered ref collection
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
8
|
import { zenWindow } from './env.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* SSR-safe event subscription. Returns disposer.
|
|
13
|
-
* @param {EventTarget | null} target
|
|
14
|
-
* @param {string} eventName
|
|
15
|
-
* @param {EventListener} handler
|
|
16
|
-
* @param {AddEventListenerOptions | boolean} [options]
|
|
17
|
-
* @returns {() => void}
|
|
18
|
-
*/
|
|
19
9
|
export function zenOn(target, eventName, handler, options) {
|
|
20
10
|
if (!target || typeof target.addEventListener !== 'function') {
|
|
21
|
-
return () => {};
|
|
11
|
+
return () => { };
|
|
22
12
|
}
|
|
23
13
|
target.addEventListener(eventName, handler, options);
|
|
24
14
|
return () => {
|
|
25
15
|
target.removeEventListener(eventName, handler, options);
|
|
26
16
|
};
|
|
27
17
|
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Window resize handler with requestAnimationFrame throttle.
|
|
31
|
-
* Returns disposer.
|
|
32
|
-
* @param {(size: { w: number; h: number }) => void} handler
|
|
33
|
-
* @returns {() => void}
|
|
34
|
-
*/
|
|
35
18
|
export function zenResize(handler) {
|
|
36
19
|
const win = zenWindow();
|
|
37
20
|
if (!win || typeof win.addEventListener !== 'function') {
|
|
38
|
-
return () => {};
|
|
21
|
+
return () => { };
|
|
39
22
|
}
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
&& typeof
|
|
23
|
+
const activeWindow = win;
|
|
24
|
+
const hasRaf = typeof activeWindow.requestAnimationFrame === 'function'
|
|
25
|
+
&& typeof activeWindow.cancelAnimationFrame === 'function';
|
|
43
26
|
let scheduledId = null;
|
|
44
27
|
let lastW = Number.NaN;
|
|
45
28
|
let lastH = Number.NaN;
|
|
46
|
-
|
|
47
29
|
const schedule = (callback) => {
|
|
48
30
|
if (hasRaf) {
|
|
49
|
-
return
|
|
31
|
+
return activeWindow.requestAnimationFrame(callback);
|
|
50
32
|
}
|
|
51
|
-
return
|
|
33
|
+
return activeWindow.setTimeout(callback, 0);
|
|
52
34
|
};
|
|
53
|
-
|
|
54
35
|
const cancel = (id) => {
|
|
55
36
|
if (hasRaf) {
|
|
56
|
-
|
|
37
|
+
activeWindow.cancelAnimationFrame(id);
|
|
57
38
|
return;
|
|
58
39
|
}
|
|
59
|
-
|
|
40
|
+
activeWindow.clearTimeout(id);
|
|
60
41
|
};
|
|
61
|
-
|
|
62
42
|
function onResize() {
|
|
63
|
-
if (scheduledId !== null)
|
|
43
|
+
if (scheduledId !== null)
|
|
44
|
+
return;
|
|
64
45
|
scheduledId = schedule(() => {
|
|
65
46
|
scheduledId = null;
|
|
66
|
-
const w =
|
|
67
|
-
const h =
|
|
47
|
+
const w = activeWindow.innerWidth;
|
|
48
|
+
const h = activeWindow.innerHeight;
|
|
68
49
|
if (w !== lastW || h !== lastH) {
|
|
69
50
|
lastW = w;
|
|
70
51
|
lastH = h;
|
|
@@ -72,28 +53,20 @@ export function zenResize(handler) {
|
|
|
72
53
|
}
|
|
73
54
|
});
|
|
74
55
|
}
|
|
75
|
-
|
|
76
|
-
win.addEventListener('resize', onResize);
|
|
56
|
+
activeWindow.addEventListener('resize', onResize);
|
|
77
57
|
onResize();
|
|
78
|
-
|
|
79
58
|
return () => {
|
|
80
59
|
if (scheduledId !== null) {
|
|
81
60
|
cancel(scheduledId);
|
|
82
61
|
scheduledId = null;
|
|
83
62
|
}
|
|
84
|
-
|
|
63
|
+
activeWindow.removeEventListener('resize', onResize);
|
|
85
64
|
};
|
|
86
65
|
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Deterministic null-filtered collection of ref.current values.
|
|
90
|
-
* @param {...{ current?: Element | null }} refs
|
|
91
|
-
* @returns {Element[]}
|
|
92
|
-
*/
|
|
93
66
|
export function collectRefs(...refs) {
|
|
94
67
|
const out = [];
|
|
95
|
-
for (let
|
|
96
|
-
const node = refs[
|
|
68
|
+
for (let index = 0; index < refs.length; index += 1) {
|
|
69
|
+
const node = refs[index]?.current;
|
|
97
70
|
if (node && typeof node === 'object' && typeof node.nodeType === 'number') {
|
|
98
71
|
out.push(node);
|
|
99
72
|
}
|
package/dist/ref.d.ts
ADDED
package/dist/ref.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// ref.
|
|
2
|
+
// ref.ts — Zenith Runtime ref primitive
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// A structural DOM pointer. NOT reactive.
|
|
5
5
|
// ref.current is a plain property — no tracking, no proxies, no subscriptions.
|
|
@@ -10,14 +10,6 @@
|
|
|
10
10
|
// - .current is assigned by runtime at mount, before zenMount callbacks run
|
|
11
11
|
// - .current is set to null on component disposal
|
|
12
12
|
// - Reading .current does NOT register a dependency in zenEffect
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create a deterministic ref for structural DOM binding.
|
|
16
|
-
*
|
|
17
|
-
* @template T
|
|
18
|
-
* @param {T} [initialValue]
|
|
19
|
-
* @returns {{ current: T | null }}
|
|
20
|
-
*/
|
|
21
13
|
export function ref(initialValue) {
|
|
22
14
|
return { current: initialValue ?? null };
|
|
23
15
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mount a page module that already contains deterministic binding tables.
|
|
3
|
+
*
|
|
4
|
+
* @param {HTMLElement} container
|
|
5
|
+
* @param {object | function} pageModule
|
|
6
|
+
* @returns {() => void}
|
|
7
|
+
*/
|
|
8
|
+
export function mount(container: HTMLElement, pageModule: object | Function): () => void;
|
package/dist/runtime.js
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Backward-compatible mount wrapper around explicit hydrate(payload).
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
|
-
|
|
7
6
|
import { hydrate } from './hydrate.js';
|
|
8
7
|
import { cleanup } from './cleanup.js';
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
9
|
* Mount a page module that already contains deterministic binding tables.
|
|
12
10
|
*
|
|
@@ -18,19 +16,15 @@ export function mount(container, pageModule) {
|
|
|
18
16
|
if (!container || typeof container.querySelectorAll !== 'function') {
|
|
19
17
|
throw new Error('[Zenith Runtime] mount(container, pageModule) requires a DOM container');
|
|
20
18
|
}
|
|
21
|
-
|
|
22
19
|
const pageFactory = _resolvePageFactory(pageModule);
|
|
23
20
|
if (!pageFactory) {
|
|
24
21
|
throw new Error('[Zenith Runtime] mount(container, pageModule) requires default() or __zenith_page()');
|
|
25
22
|
}
|
|
26
|
-
|
|
27
23
|
const page = pageFactory();
|
|
28
24
|
if (!page || typeof page.html !== 'string') {
|
|
29
25
|
throw new Error('[Zenith Runtime] __zenith_page() must return an object with html');
|
|
30
26
|
}
|
|
31
|
-
|
|
32
27
|
container.innerHTML = page.html;
|
|
33
|
-
|
|
34
28
|
hydrate({
|
|
35
29
|
root: container,
|
|
36
30
|
ir_version: page.ir_version,
|
|
@@ -41,17 +35,19 @@ export function mount(container, pageModule) {
|
|
|
41
35
|
signals: Array.isArray(page.signals) ? page.signals : [],
|
|
42
36
|
components: Array.isArray(page.components) ? page.components : []
|
|
43
37
|
});
|
|
44
|
-
|
|
45
38
|
return function unmount() {
|
|
46
39
|
cleanup();
|
|
47
40
|
container.innerHTML = '';
|
|
48
41
|
};
|
|
49
42
|
}
|
|
50
|
-
|
|
51
43
|
function _resolvePageFactory(pageModule) {
|
|
52
|
-
if (typeof pageModule === 'function')
|
|
53
|
-
|
|
54
|
-
if (typeof pageModule
|
|
55
|
-
|
|
44
|
+
if (typeof pageModule === 'function')
|
|
45
|
+
return pageModule;
|
|
46
|
+
if (!pageModule || typeof pageModule !== 'object')
|
|
47
|
+
return null;
|
|
48
|
+
if (typeof pageModule.default === 'function')
|
|
49
|
+
return pageModule.default;
|
|
50
|
+
if (typeof pageModule.__zenith_page === 'function')
|
|
51
|
+
return pageModule.__zenith_page;
|
|
56
52
|
return null;
|
|
57
53
|
}
|
package/dist/signal.d.ts
ADDED
package/dist/signal.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// signal.
|
|
2
|
+
// signal.ts — Zenith Runtime V0
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Minimal explicit signal primitive.
|
|
5
5
|
//
|
|
@@ -16,18 +16,10 @@
|
|
|
16
16
|
// - No async queue
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
18
|
import { _nextReactiveId, _trackDependency } from './zeneffect.js';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Create a deterministic signal with explicit subscription semantics.
|
|
22
|
-
*
|
|
23
|
-
* @param {*} initialValue
|
|
24
|
-
* @returns {{ get: () => *, set: (next: *) => *, subscribe: (fn: (value: *) => void) => () => void }}
|
|
25
|
-
*/
|
|
26
19
|
export function signal(initialValue) {
|
|
27
20
|
let value = initialValue;
|
|
28
21
|
const subscribers = new Set();
|
|
29
22
|
const reactiveId = _nextReactiveId();
|
|
30
|
-
|
|
31
23
|
return {
|
|
32
24
|
__zenith_id: reactiveId,
|
|
33
25
|
get() {
|
|
@@ -38,21 +30,17 @@ export function signal(initialValue) {
|
|
|
38
30
|
if (Object.is(value, nextValue)) {
|
|
39
31
|
return value;
|
|
40
32
|
}
|
|
41
|
-
|
|
42
33
|
value = nextValue;
|
|
43
|
-
|
|
44
34
|
const snapshot = [...subscribers];
|
|
45
|
-
for (let
|
|
46
|
-
snapshot[
|
|
35
|
+
for (let index = 0; index < snapshot.length; index += 1) {
|
|
36
|
+
snapshot[index](value);
|
|
47
37
|
}
|
|
48
|
-
|
|
49
38
|
return value;
|
|
50
39
|
},
|
|
51
40
|
subscribe(fn) {
|
|
52
41
|
if (typeof fn !== 'function') {
|
|
53
42
|
throw new Error('[Zenith Runtime] signal.subscribe(fn) requires a function');
|
|
54
43
|
}
|
|
55
|
-
|
|
56
44
|
subscribers.add(fn);
|
|
57
45
|
return function unsubscribe() {
|
|
58
46
|
subscribers.delete(fn);
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type PlainState = Record<string, unknown>;
|
|
2
|
+
type StateUpdater<T extends PlainState> = T | ((prev: Readonly<T>) => T);
|
|
3
|
+
export type ZenithState<T extends PlainState> = {
|
|
4
|
+
__zenith_id: number;
|
|
5
|
+
get(): Readonly<T>;
|
|
6
|
+
set(patch: StateUpdater<T>): Readonly<T>;
|
|
7
|
+
subscribe(fn: (next: Readonly<T>) => void): () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function state<T extends PlainState>(initialValue: T): ZenithState<T>;
|
|
10
|
+
export {};
|
package/dist/state.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// state.
|
|
2
|
+
// state.ts — Zenith Runtime V0
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Proxy-free immutable state helper.
|
|
5
5
|
//
|
|
@@ -10,14 +10,12 @@
|
|
|
10
10
|
// store.set((prev) => ({ ...prev, count: prev.count + 1 }));
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
import { _nextReactiveId, _trackDependency } from './zeneffect.js';
|
|
13
|
-
|
|
14
13
|
function isPlainObject(value) {
|
|
15
14
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
16
15
|
return false;
|
|
17
16
|
}
|
|
18
17
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
19
18
|
}
|
|
20
|
-
|
|
21
19
|
function cloneSnapshot(value) {
|
|
22
20
|
if (Array.isArray(value)) {
|
|
23
21
|
return [...value];
|
|
@@ -27,18 +25,10 @@ function cloneSnapshot(value) {
|
|
|
27
25
|
}
|
|
28
26
|
return value;
|
|
29
27
|
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Create a proxy-free immutable state container.
|
|
33
|
-
*
|
|
34
|
-
* @param {object} initialValue
|
|
35
|
-
* @returns {{ get: () => object, set: (patch: object | ((prev: object) => object)) => object, subscribe: (fn: (next: object) => void) => () => void }}
|
|
36
|
-
*/
|
|
37
28
|
export function state(initialValue) {
|
|
38
29
|
let current = Object.freeze(cloneSnapshot(initialValue));
|
|
39
30
|
const subscribers = new Set();
|
|
40
31
|
const reactiveId = _nextReactiveId();
|
|
41
|
-
|
|
42
32
|
return {
|
|
43
33
|
__zenith_id: reactiveId,
|
|
44
34
|
get() {
|
|
@@ -49,30 +39,24 @@ export function state(initialValue) {
|
|
|
49
39
|
const nextValue = typeof nextPatch === 'function'
|
|
50
40
|
? nextPatch(current)
|
|
51
41
|
: { ...current, ...nextPatch };
|
|
52
|
-
|
|
53
|
-
if (!nextValue || typeof nextValue !== 'object' || Array.isArray(nextValue)) {
|
|
42
|
+
if (!isPlainObject(nextValue)) {
|
|
54
43
|
throw new Error('[Zenith Runtime] state.set(next) must resolve to a plain object');
|
|
55
44
|
}
|
|
56
|
-
|
|
57
45
|
const nextSnapshot = Object.freeze(cloneSnapshot(nextValue));
|
|
58
46
|
if (Object.is(current, nextSnapshot)) {
|
|
59
47
|
return current;
|
|
60
48
|
}
|
|
61
|
-
|
|
62
49
|
current = nextSnapshot;
|
|
63
|
-
|
|
64
50
|
const snapshot = [...subscribers];
|
|
65
|
-
for (let
|
|
66
|
-
snapshot[
|
|
51
|
+
for (let index = 0; index < snapshot.length; index += 1) {
|
|
52
|
+
snapshot[index](current);
|
|
67
53
|
}
|
|
68
|
-
|
|
69
54
|
return current;
|
|
70
55
|
},
|
|
71
56
|
subscribe(fn) {
|
|
72
57
|
if (typeof fn !== 'function') {
|
|
73
58
|
throw new Error('[Zenith Runtime] state.subscribe(fn) requires a function');
|
|
74
59
|
}
|
|
75
|
-
|
|
76
60
|
subscribers.add(fn);
|
|
77
61
|
return function unsubscribe() {
|
|
78
62
|
subscribers.delete(fn);
|
package/dist/template.js
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
4
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
5
|
const __dirname = dirname(__filename);
|
|
7
|
-
|
|
8
6
|
function normalizeNewlines(value) {
|
|
9
7
|
return String(value).replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
10
8
|
}
|
|
11
|
-
|
|
12
9
|
function readRuntimeSourceFile(fileName) {
|
|
13
10
|
const fullPath = join(__dirname, fileName);
|
|
14
11
|
return normalizeNewlines(readFileSync(fullPath, 'utf8'));
|
|
15
12
|
}
|
|
16
|
-
|
|
17
13
|
function stripImports(source) {
|
|
18
14
|
return source.replace(/^\s*import\s+[^;]+;\s*$/gm, '').trim();
|
|
19
15
|
}
|
|
20
|
-
|
|
21
16
|
function buildRuntimeModuleSource() {
|
|
22
17
|
const segments = [
|
|
23
18
|
stripImports(readRuntimeSourceFile('zeneffect.js')),
|
|
@@ -30,16 +25,12 @@ function buildRuntimeModuleSource() {
|
|
|
30
25
|
stripImports(readRuntimeSourceFile('cleanup.js')),
|
|
31
26
|
stripImports(readRuntimeSourceFile('hydrate.js'))
|
|
32
27
|
].filter(Boolean);
|
|
33
|
-
|
|
34
28
|
return normalizeNewlines(segments.join('\n\n'));
|
|
35
29
|
}
|
|
36
|
-
|
|
37
30
|
const RUNTIME_MODULE_SOURCE = buildRuntimeModuleSource();
|
|
38
|
-
|
|
39
31
|
export function runtimeModuleSource() {
|
|
40
32
|
return RUNTIME_MODULE_SOURCE;
|
|
41
33
|
}
|
|
42
|
-
|
|
43
34
|
const RUNTIME_DEV_CLIENT_SOURCE = `(() => {
|
|
44
35
|
if (typeof window === 'undefined' || typeof document === 'undefined') return;
|
|
45
36
|
if (window.__zenithDevClientActive === true) return;
|
|
@@ -441,7 +432,6 @@ const RUNTIME_DEV_CLIENT_SOURCE = `(() => {
|
|
|
441
432
|
appendLog('[error] lost dev server connection');
|
|
442
433
|
});
|
|
443
434
|
})();`;
|
|
444
|
-
|
|
445
435
|
export function runtimeDevClientSource() {
|
|
446
436
|
return RUNTIME_DEV_CLIENT_SOURCE;
|
|
447
437
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function _nextReactiveId(): number;
|
|
2
|
+
export declare function _trackDependency(source: any): void;
|
|
3
|
+
export declare function resetGlobalSideEffects(): void;
|
|
4
|
+
export declare function createSideEffectScope(label?: string): {
|
|
5
|
+
__zenith_scope: boolean;
|
|
6
|
+
id: number;
|
|
7
|
+
label: any;
|
|
8
|
+
mountReady: boolean;
|
|
9
|
+
disposed: boolean;
|
|
10
|
+
pendingMounts: never[];
|
|
11
|
+
disposers: never[];
|
|
12
|
+
};
|
|
13
|
+
export declare function activateSideEffectScope(scope: any): void;
|
|
14
|
+
export declare function disposeSideEffectScope(scope: any): void;
|
|
15
|
+
export declare function zenEffect(effect: any, options?: null, scopeOverride?: null): () => void;
|
|
16
|
+
export declare function zeneffect(effectOrDependencies: any, optionsOrEffect: any, scopeOverride?: null): () => void;
|
|
17
|
+
export declare function zenMount(callback: any, scopeOverride?: null): () => void;
|