@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/zeneffect.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// zeneffect.
|
|
3
|
+
// zeneffect.ts — Zenith Runtime V0
|
|
3
4
|
// ---------------------------------------------------------------------------
|
|
4
5
|
// Explicit dependency effect primitive.
|
|
5
6
|
//
|
|
@@ -12,30 +13,25 @@
|
|
|
12
13
|
// - No scheduler
|
|
13
14
|
// - No async queue
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
16
|
const DEFAULT_EFFECT_OPTIONS = {
|
|
17
17
|
debounceMs: 0,
|
|
18
18
|
throttleMs: 0,
|
|
19
19
|
raf: false,
|
|
20
20
|
flush: 'post'
|
|
21
21
|
};
|
|
22
|
-
|
|
23
22
|
let _activeDependencyCollector = null;
|
|
24
23
|
let _reactiveIdCounter = 0;
|
|
25
24
|
let _scopeIdCounter = 0;
|
|
26
25
|
let _effectIdCounter = 0;
|
|
27
|
-
|
|
28
26
|
export function _nextReactiveId() {
|
|
29
27
|
_reactiveIdCounter += 1;
|
|
30
28
|
return _reactiveIdCounter;
|
|
31
29
|
}
|
|
32
|
-
|
|
33
30
|
export function _trackDependency(source) {
|
|
34
31
|
if (typeof _activeDependencyCollector === 'function') {
|
|
35
32
|
_activeDependencyCollector(source);
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
|
-
|
|
39
35
|
function createInternalScope(label, mountReady) {
|
|
40
36
|
_scopeIdCounter += 1;
|
|
41
37
|
return {
|
|
@@ -48,61 +44,51 @@ function createInternalScope(label, mountReady) {
|
|
|
48
44
|
disposers: []
|
|
49
45
|
};
|
|
50
46
|
}
|
|
51
|
-
|
|
52
47
|
let _globalScope = createInternalScope('global', true);
|
|
53
|
-
|
|
54
48
|
function isScope(value) {
|
|
55
49
|
return !!value && typeof value === 'object' && value.__zenith_scope === true;
|
|
56
50
|
}
|
|
57
|
-
|
|
58
51
|
function resolveScope(scopeOverride) {
|
|
59
52
|
if (isScope(scopeOverride)) {
|
|
60
53
|
return scopeOverride;
|
|
61
54
|
}
|
|
62
55
|
return _globalScope;
|
|
63
56
|
}
|
|
64
|
-
|
|
65
57
|
export function resetGlobalSideEffects() {
|
|
66
58
|
disposeSideEffectScope(_globalScope);
|
|
67
59
|
_globalScope = createInternalScope('global', true);
|
|
68
60
|
}
|
|
69
|
-
|
|
70
61
|
export function createSideEffectScope(label = 'anonymous') {
|
|
71
62
|
return createInternalScope(label, false);
|
|
72
63
|
}
|
|
73
|
-
|
|
74
64
|
export function activateSideEffectScope(scope) {
|
|
75
65
|
if (!isScope(scope) || scope.disposed || scope.mountReady) {
|
|
76
66
|
return;
|
|
77
67
|
}
|
|
78
68
|
scope.mountReady = true;
|
|
79
|
-
|
|
80
69
|
const pending = scope.pendingMounts.slice();
|
|
81
70
|
scope.pendingMounts.length = 0;
|
|
82
|
-
|
|
83
71
|
for (let i = 0; i < pending.length; i++) {
|
|
84
72
|
const callback = pending[i];
|
|
85
|
-
if (typeof callback !== 'function')
|
|
73
|
+
if (typeof callback !== 'function')
|
|
74
|
+
continue;
|
|
86
75
|
try {
|
|
87
76
|
callback();
|
|
88
|
-
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
89
79
|
// failed effect mounts should not crash sibling nodes
|
|
90
80
|
}
|
|
91
81
|
}
|
|
92
82
|
}
|
|
93
|
-
|
|
94
83
|
function registerScopeDisposer(scope, disposer) {
|
|
95
84
|
if (typeof disposer !== 'function') {
|
|
96
85
|
return () => { };
|
|
97
86
|
}
|
|
98
|
-
|
|
99
87
|
if (!scope || scope.disposed) {
|
|
100
88
|
disposer();
|
|
101
89
|
return () => { };
|
|
102
90
|
}
|
|
103
|
-
|
|
104
91
|
scope.disposers.push(disposer);
|
|
105
|
-
|
|
106
92
|
return function unregisterScopeDisposer() {
|
|
107
93
|
if (!scope || scope.disposed) {
|
|
108
94
|
return;
|
|
@@ -113,18 +99,14 @@ function registerScopeDisposer(scope, disposer) {
|
|
|
113
99
|
}
|
|
114
100
|
};
|
|
115
101
|
}
|
|
116
|
-
|
|
117
102
|
export function disposeSideEffectScope(scope) {
|
|
118
103
|
if (!scope || scope.disposed) {
|
|
119
104
|
return;
|
|
120
105
|
}
|
|
121
|
-
|
|
122
106
|
scope.disposed = true;
|
|
123
|
-
|
|
124
107
|
const disposers = scope.disposers.slice();
|
|
125
108
|
scope.disposers.length = 0;
|
|
126
109
|
scope.pendingMounts.length = 0;
|
|
127
|
-
|
|
128
110
|
for (let i = disposers.length - 1; i >= 0; i--) {
|
|
129
111
|
const disposer = disposers[i];
|
|
130
112
|
if (typeof disposer !== 'function') {
|
|
@@ -132,56 +114,45 @@ export function disposeSideEffectScope(scope) {
|
|
|
132
114
|
}
|
|
133
115
|
try {
|
|
134
116
|
disposer();
|
|
135
|
-
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
136
119
|
// cleanup failures must never break teardown flow
|
|
137
120
|
}
|
|
138
121
|
}
|
|
139
122
|
}
|
|
140
|
-
|
|
141
123
|
function normalizeDelay(value, fieldName) {
|
|
142
124
|
if (value === undefined || value === null) {
|
|
143
125
|
return 0;
|
|
144
126
|
}
|
|
145
127
|
if (!Number.isFinite(value) || value < 0) {
|
|
146
|
-
throw new Error(
|
|
147
|
-
`[Zenith Runtime] zenEffect options.${fieldName} must be a non-negative number`
|
|
148
|
-
);
|
|
128
|
+
throw new Error(`[Zenith Runtime] zenEffect options.${fieldName} must be a non-negative number`);
|
|
149
129
|
}
|
|
150
130
|
return Math.floor(value);
|
|
151
131
|
}
|
|
152
|
-
|
|
153
132
|
function normalizeEffectOptions(options) {
|
|
154
133
|
if (options === undefined || options === null) {
|
|
155
134
|
return DEFAULT_EFFECT_OPTIONS;
|
|
156
135
|
}
|
|
157
|
-
|
|
158
136
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
159
137
|
throw new Error('[Zenith Runtime] zenEffect(effect, options) requires options object when provided');
|
|
160
138
|
}
|
|
161
|
-
|
|
162
139
|
const normalized = {
|
|
163
140
|
debounceMs: normalizeDelay(options.debounceMs, 'debounceMs'),
|
|
164
141
|
throttleMs: normalizeDelay(options.throttleMs, 'throttleMs'),
|
|
165
142
|
raf: options.raf === true,
|
|
166
143
|
flush: options.flush === 'sync' ? 'sync' : 'post'
|
|
167
144
|
};
|
|
168
|
-
|
|
169
145
|
if (options.flush !== undefined && options.flush !== 'sync' && options.flush !== 'post') {
|
|
170
146
|
throw new Error('[Zenith Runtime] zenEffect options.flush must be "post" or "sync"');
|
|
171
147
|
}
|
|
172
|
-
|
|
173
|
-
const schedulingModes =
|
|
174
|
-
(normalized.debounceMs > 0 ? 1 : 0) +
|
|
148
|
+
const schedulingModes = (normalized.debounceMs > 0 ? 1 : 0) +
|
|
175
149
|
(normalized.throttleMs > 0 ? 1 : 0) +
|
|
176
150
|
(normalized.raf ? 1 : 0);
|
|
177
|
-
|
|
178
151
|
if (schedulingModes > 1) {
|
|
179
152
|
throw new Error('[Zenith Runtime] zenEffect options may use only one scheduler: debounceMs, throttleMs, or raf');
|
|
180
153
|
}
|
|
181
|
-
|
|
182
154
|
return normalized;
|
|
183
155
|
}
|
|
184
|
-
|
|
185
156
|
function drainCleanupStack(cleanups) {
|
|
186
157
|
for (let i = cleanups.length - 1; i >= 0; i--) {
|
|
187
158
|
const cleanup = cleanups[i];
|
|
@@ -190,36 +161,32 @@ function drainCleanupStack(cleanups) {
|
|
|
190
161
|
}
|
|
191
162
|
try {
|
|
192
163
|
cleanup();
|
|
193
|
-
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
194
166
|
// swallow cleanup errors to preserve deterministic teardown
|
|
195
167
|
}
|
|
196
168
|
}
|
|
197
169
|
cleanups.length = 0;
|
|
198
170
|
}
|
|
199
|
-
|
|
200
171
|
function applyCleanupResult(result, registerCleanup) {
|
|
201
172
|
if (typeof result === 'function') {
|
|
202
173
|
registerCleanup(result);
|
|
203
174
|
return;
|
|
204
175
|
}
|
|
205
|
-
|
|
206
176
|
if (result && typeof result === 'object' && typeof result.cleanup === 'function') {
|
|
207
177
|
registerCleanup(result.cleanup);
|
|
208
178
|
}
|
|
209
179
|
}
|
|
210
|
-
|
|
211
180
|
function requireFunction(callback, label) {
|
|
212
181
|
if (typeof callback !== 'function') {
|
|
213
182
|
throw new Error(`[Zenith Runtime] ${label} requires callback function`);
|
|
214
183
|
}
|
|
215
184
|
}
|
|
216
|
-
|
|
217
185
|
function createMountContext(registerCleanup) {
|
|
218
186
|
return {
|
|
219
187
|
cleanup: registerCleanup
|
|
220
188
|
};
|
|
221
189
|
}
|
|
222
|
-
|
|
223
190
|
function createEffectContext(registerCleanup) {
|
|
224
191
|
return {
|
|
225
192
|
cleanup: registerCleanup,
|
|
@@ -244,7 +211,6 @@ function createEffectContext(registerCleanup) {
|
|
|
244
211
|
requireFunction(callback, 'zenEffect context.debounce(callback, delayMs)');
|
|
245
212
|
const waitMs = normalizeDelay(delayMs, 'debounce');
|
|
246
213
|
let timeoutId = null;
|
|
247
|
-
|
|
248
214
|
const wrapped = (...args) => {
|
|
249
215
|
if (timeoutId !== null) {
|
|
250
216
|
clearTimeout(timeoutId);
|
|
@@ -254,14 +220,12 @@ function createEffectContext(registerCleanup) {
|
|
|
254
220
|
callback(...args);
|
|
255
221
|
}, waitMs);
|
|
256
222
|
};
|
|
257
|
-
|
|
258
223
|
registerCleanup(() => {
|
|
259
224
|
if (timeoutId !== null) {
|
|
260
225
|
clearTimeout(timeoutId);
|
|
261
226
|
timeoutId = null;
|
|
262
227
|
}
|
|
263
228
|
});
|
|
264
|
-
|
|
265
229
|
return wrapped;
|
|
266
230
|
},
|
|
267
231
|
throttle(callback, delayMs) {
|
|
@@ -270,12 +234,10 @@ function createEffectContext(registerCleanup) {
|
|
|
270
234
|
let timeoutId = null;
|
|
271
235
|
let lastRun = 0;
|
|
272
236
|
let pendingArgs = null;
|
|
273
|
-
|
|
274
237
|
const invoke = (args) => {
|
|
275
238
|
lastRun = Date.now();
|
|
276
239
|
callback(...args);
|
|
277
240
|
};
|
|
278
|
-
|
|
279
241
|
const wrapped = (...args) => {
|
|
280
242
|
const now = Date.now();
|
|
281
243
|
const elapsed = now - lastRun;
|
|
@@ -288,12 +250,10 @@ function createEffectContext(registerCleanup) {
|
|
|
288
250
|
invoke(args);
|
|
289
251
|
return;
|
|
290
252
|
}
|
|
291
|
-
|
|
292
253
|
pendingArgs = args;
|
|
293
254
|
if (timeoutId !== null) {
|
|
294
255
|
return;
|
|
295
256
|
}
|
|
296
|
-
|
|
297
257
|
timeoutId = setTimeout(() => {
|
|
298
258
|
timeoutId = null;
|
|
299
259
|
if (pendingArgs) {
|
|
@@ -303,7 +263,6 @@ function createEffectContext(registerCleanup) {
|
|
|
303
263
|
}
|
|
304
264
|
}, waitMs - elapsed);
|
|
305
265
|
};
|
|
306
|
-
|
|
307
266
|
registerCleanup(() => {
|
|
308
267
|
if (timeoutId !== null) {
|
|
309
268
|
clearTimeout(timeoutId);
|
|
@@ -311,19 +270,16 @@ function createEffectContext(registerCleanup) {
|
|
|
311
270
|
}
|
|
312
271
|
pendingArgs = null;
|
|
313
272
|
});
|
|
314
|
-
|
|
315
273
|
return wrapped;
|
|
316
274
|
}
|
|
317
275
|
};
|
|
318
276
|
}
|
|
319
|
-
|
|
320
277
|
function createScheduler(runNow, options) {
|
|
321
278
|
let microtaskQueued = false;
|
|
322
279
|
let debounceTimer = null;
|
|
323
280
|
let throttleTimer = null;
|
|
324
281
|
let rafHandle = null;
|
|
325
282
|
let lastRunAt = 0;
|
|
326
|
-
|
|
327
283
|
function clearScheduledWork() {
|
|
328
284
|
if (debounceTimer !== null) {
|
|
329
285
|
clearTimeout(debounceTimer);
|
|
@@ -336,14 +292,14 @@ function createScheduler(runNow, options) {
|
|
|
336
292
|
if (rafHandle !== null) {
|
|
337
293
|
if (typeof cancelAnimationFrame === 'function') {
|
|
338
294
|
cancelAnimationFrame(rafHandle);
|
|
339
|
-
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
340
297
|
clearTimeout(rafHandle);
|
|
341
298
|
}
|
|
342
299
|
rafHandle = null;
|
|
343
300
|
}
|
|
344
301
|
microtaskQueued = false;
|
|
345
302
|
}
|
|
346
|
-
|
|
347
303
|
function invokeNow() {
|
|
348
304
|
microtaskQueued = false;
|
|
349
305
|
debounceTimer = null;
|
|
@@ -352,7 +308,6 @@ function createScheduler(runNow, options) {
|
|
|
352
308
|
lastRunAt = Date.now();
|
|
353
309
|
runNow();
|
|
354
310
|
}
|
|
355
|
-
|
|
356
311
|
function schedule() {
|
|
357
312
|
if (options.debounceMs > 0) {
|
|
358
313
|
if (debounceTimer !== null) {
|
|
@@ -361,7 +316,6 @@ function createScheduler(runNow, options) {
|
|
|
361
316
|
debounceTimer = setTimeout(invokeNow, options.debounceMs);
|
|
362
317
|
return;
|
|
363
318
|
}
|
|
364
|
-
|
|
365
319
|
if (options.throttleMs > 0) {
|
|
366
320
|
const now = Date.now();
|
|
367
321
|
const elapsed = now - lastRunAt;
|
|
@@ -369,50 +323,44 @@ function createScheduler(runNow, options) {
|
|
|
369
323
|
invokeNow();
|
|
370
324
|
return;
|
|
371
325
|
}
|
|
372
|
-
|
|
373
326
|
if (throttleTimer !== null) {
|
|
374
327
|
return;
|
|
375
328
|
}
|
|
376
|
-
|
|
377
329
|
throttleTimer = setTimeout(invokeNow, options.throttleMs - elapsed);
|
|
378
330
|
return;
|
|
379
331
|
}
|
|
380
|
-
|
|
381
332
|
if (options.raf) {
|
|
382
333
|
if (rafHandle !== null) {
|
|
383
334
|
if (typeof cancelAnimationFrame === 'function') {
|
|
384
335
|
cancelAnimationFrame(rafHandle);
|
|
385
|
-
}
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
386
338
|
clearTimeout(rafHandle);
|
|
387
339
|
}
|
|
388
340
|
}
|
|
389
|
-
|
|
390
341
|
if (typeof requestAnimationFrame === 'function') {
|
|
391
342
|
rafHandle = requestAnimationFrame(invokeNow);
|
|
392
|
-
}
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
393
345
|
rafHandle = setTimeout(invokeNow, 16);
|
|
394
346
|
}
|
|
395
347
|
return;
|
|
396
348
|
}
|
|
397
|
-
|
|
398
349
|
if (options.flush === 'sync') {
|
|
399
350
|
invokeNow();
|
|
400
351
|
return;
|
|
401
352
|
}
|
|
402
|
-
|
|
403
353
|
if (microtaskQueued) {
|
|
404
354
|
return;
|
|
405
355
|
}
|
|
406
356
|
microtaskQueued = true;
|
|
407
357
|
queueMicrotask(invokeNow);
|
|
408
358
|
}
|
|
409
|
-
|
|
410
359
|
return {
|
|
411
360
|
schedule,
|
|
412
361
|
cancel: clearScheduledWork
|
|
413
362
|
};
|
|
414
363
|
}
|
|
415
|
-
|
|
416
364
|
function queueWhenScopeReady(scope, callback) {
|
|
417
365
|
if (!scope || scope.disposed) {
|
|
418
366
|
return;
|
|
@@ -423,32 +371,25 @@ function queueWhenScopeReady(scope, callback) {
|
|
|
423
371
|
}
|
|
424
372
|
scope.pendingMounts.push(callback);
|
|
425
373
|
}
|
|
426
|
-
|
|
427
374
|
function createAutoTrackedEffect(effect, options, scope) {
|
|
428
375
|
let disposed = false;
|
|
429
376
|
const activeSubscriptions = new Map();
|
|
430
377
|
const runCleanups = [];
|
|
431
|
-
|
|
432
378
|
_effectIdCounter += 1;
|
|
433
379
|
const effectId = _effectIdCounter;
|
|
434
|
-
|
|
435
380
|
function registerCleanup(cleanup) {
|
|
436
381
|
if (typeof cleanup !== 'function') {
|
|
437
382
|
throw new Error('[Zenith Runtime] cleanup(fn) requires a function');
|
|
438
383
|
}
|
|
439
384
|
runCleanups.push(cleanup);
|
|
440
385
|
}
|
|
441
|
-
|
|
442
386
|
function runEffectNow() {
|
|
443
387
|
if (disposed || !scope || scope.disposed) {
|
|
444
388
|
return;
|
|
445
389
|
}
|
|
446
|
-
|
|
447
390
|
drainCleanupStack(runCleanups);
|
|
448
|
-
|
|
449
391
|
const nextDependenciesById = new Map();
|
|
450
392
|
const previousCollector = _activeDependencyCollector;
|
|
451
|
-
|
|
452
393
|
_activeDependencyCollector = (source) => {
|
|
453
394
|
if (!source || typeof source.subscribe !== 'function') {
|
|
454
395
|
return;
|
|
@@ -458,22 +399,19 @@ function createAutoTrackedEffect(effect, options, scope) {
|
|
|
458
399
|
nextDependenciesById.set(reactiveId, source);
|
|
459
400
|
}
|
|
460
401
|
};
|
|
461
|
-
|
|
462
402
|
try {
|
|
463
403
|
const result = effect(createEffectContext(registerCleanup));
|
|
464
404
|
applyCleanupResult(result, registerCleanup);
|
|
465
|
-
}
|
|
405
|
+
}
|
|
406
|
+
finally {
|
|
466
407
|
_activeDependencyCollector = previousCollector;
|
|
467
408
|
}
|
|
468
|
-
|
|
469
409
|
const nextDependencies = Array.from(nextDependenciesById.values()).sort((left, right) => {
|
|
470
410
|
const leftId = Number.isInteger(left.__zenith_id) ? left.__zenith_id : 0;
|
|
471
411
|
const rightId = Number.isInteger(right.__zenith_id) ? right.__zenith_id : 0;
|
|
472
412
|
return leftId - rightId;
|
|
473
413
|
});
|
|
474
|
-
|
|
475
414
|
const nextSet = new Set(nextDependencies);
|
|
476
|
-
|
|
477
415
|
for (const [dependency, unsubscribe] of activeSubscriptions.entries()) {
|
|
478
416
|
if (nextSet.has(dependency)) {
|
|
479
417
|
continue;
|
|
@@ -483,95 +421,70 @@ function createAutoTrackedEffect(effect, options, scope) {
|
|
|
483
421
|
}
|
|
484
422
|
activeSubscriptions.delete(dependency);
|
|
485
423
|
}
|
|
486
|
-
|
|
487
424
|
for (let i = 0; i < nextDependencies.length; i++) {
|
|
488
425
|
const dependency = nextDependencies[i];
|
|
489
426
|
if (activeSubscriptions.has(dependency)) {
|
|
490
427
|
continue;
|
|
491
428
|
}
|
|
492
|
-
|
|
493
429
|
const unsubscribe = dependency.subscribe(() => {
|
|
494
430
|
scheduler.schedule();
|
|
495
431
|
});
|
|
496
|
-
|
|
497
|
-
activeSubscriptions.set(
|
|
498
|
-
dependency,
|
|
499
|
-
typeof unsubscribe === 'function' ? unsubscribe : () => { }
|
|
500
|
-
);
|
|
432
|
+
activeSubscriptions.set(dependency, typeof unsubscribe === 'function' ? unsubscribe : () => { });
|
|
501
433
|
}
|
|
502
|
-
|
|
503
434
|
void effectId;
|
|
504
435
|
}
|
|
505
|
-
|
|
506
436
|
const scheduler = createScheduler(runEffectNow, options);
|
|
507
|
-
|
|
508
437
|
function disposeEffect() {
|
|
509
438
|
if (disposed) {
|
|
510
439
|
return;
|
|
511
440
|
}
|
|
512
441
|
disposed = true;
|
|
513
|
-
|
|
514
442
|
scheduler.cancel();
|
|
515
|
-
|
|
516
443
|
for (const unsubscribe of activeSubscriptions.values()) {
|
|
517
444
|
if (typeof unsubscribe === 'function') {
|
|
518
445
|
unsubscribe();
|
|
519
446
|
}
|
|
520
447
|
}
|
|
521
448
|
activeSubscriptions.clear();
|
|
522
|
-
|
|
523
449
|
drainCleanupStack(runCleanups);
|
|
524
450
|
}
|
|
525
|
-
|
|
526
451
|
registerScopeDisposer(scope, disposeEffect);
|
|
527
452
|
queueWhenScopeReady(scope, () => scheduler.schedule());
|
|
528
|
-
|
|
529
453
|
return disposeEffect;
|
|
530
454
|
}
|
|
531
|
-
|
|
532
455
|
function createExplicitDependencyEffect(effect, dependencies, scope) {
|
|
533
456
|
if (!Array.isArray(dependencies)) {
|
|
534
457
|
throw new Error('[Zenith Runtime] zeneffect(deps, fn) requires an array of dependencies');
|
|
535
458
|
}
|
|
536
|
-
|
|
537
459
|
if (dependencies.length === 0) {
|
|
538
460
|
throw new Error('[Zenith Runtime] zeneffect(deps, fn) requires at least one dependency');
|
|
539
461
|
}
|
|
540
|
-
|
|
541
462
|
if (typeof effect !== 'function') {
|
|
542
463
|
throw new Error('[Zenith Runtime] zeneffect(deps, fn) requires a function');
|
|
543
464
|
}
|
|
544
|
-
|
|
545
465
|
const unsubscribers = dependencies.map((dep, index) => {
|
|
546
466
|
if (!dep || typeof dep.subscribe !== 'function') {
|
|
547
467
|
throw new Error(`[Zenith Runtime] zeneffect dependency at index ${index} must expose subscribe(fn)`);
|
|
548
468
|
}
|
|
549
|
-
|
|
550
469
|
return dep.subscribe(() => {
|
|
551
470
|
effect();
|
|
552
471
|
});
|
|
553
472
|
});
|
|
554
|
-
|
|
555
473
|
effect();
|
|
556
|
-
|
|
557
474
|
return function dispose() {
|
|
558
475
|
for (let i = 0; i < unsubscribers.length; i++) {
|
|
559
476
|
unsubscribers[i]();
|
|
560
477
|
}
|
|
561
478
|
};
|
|
562
479
|
}
|
|
563
|
-
|
|
564
480
|
export function zenEffect(effect, options = null, scopeOverride = null) {
|
|
565
481
|
if (typeof effect !== 'function') {
|
|
566
482
|
throw new Error('[Zenith Runtime] zenEffect(effect) requires a callback function');
|
|
567
483
|
}
|
|
568
|
-
|
|
569
484
|
const opts = normalizeEffectOptions(options);
|
|
570
485
|
const scope = resolveScope(scopeOverride);
|
|
571
|
-
|
|
572
486
|
return createAutoTrackedEffect(effect, opts, scope);
|
|
573
487
|
}
|
|
574
|
-
|
|
575
488
|
export function zeneffect(effectOrDependencies, optionsOrEffect, scopeOverride = null) {
|
|
576
489
|
if (Array.isArray(effectOrDependencies)) {
|
|
577
490
|
if (typeof optionsOrEffect !== 'function') {
|
|
@@ -579,61 +492,48 @@ export function zeneffect(effectOrDependencies, optionsOrEffect, scopeOverride =
|
|
|
579
492
|
}
|
|
580
493
|
return createExplicitDependencyEffect(optionsOrEffect, effectOrDependencies, resolveScope(scopeOverride));
|
|
581
494
|
}
|
|
582
|
-
|
|
583
495
|
if (typeof effectOrDependencies === 'function') {
|
|
584
|
-
return createAutoTrackedEffect(
|
|
585
|
-
effectOrDependencies,
|
|
586
|
-
normalizeEffectOptions(optionsOrEffect),
|
|
587
|
-
resolveScope(scopeOverride)
|
|
588
|
-
);
|
|
496
|
+
return createAutoTrackedEffect(effectOrDependencies, normalizeEffectOptions(optionsOrEffect), resolveScope(scopeOverride));
|
|
589
497
|
}
|
|
590
|
-
|
|
591
498
|
throw new Error('[Zenith Runtime] zeneffect() invalid arguments. Expected (effect) or (dependencies, effect)');
|
|
592
499
|
}
|
|
593
|
-
|
|
594
500
|
export function zenMount(callback, scopeOverride = null) {
|
|
595
501
|
if (typeof callback !== 'function') {
|
|
596
502
|
throw new Error('[Zenith Runtime] zenMount(callback) requires a function');
|
|
597
503
|
}
|
|
598
|
-
|
|
599
504
|
const scope = resolveScope(scopeOverride);
|
|
600
505
|
const cleanups = [];
|
|
601
506
|
let executed = false;
|
|
602
507
|
let registeredDisposer = null;
|
|
603
|
-
|
|
604
508
|
function registerCleanup(fn) {
|
|
605
509
|
if (typeof fn !== 'function') {
|
|
606
510
|
throw new Error('[Zenith Runtime] cleanup(fn) requires a function');
|
|
607
511
|
}
|
|
608
512
|
cleanups.push(fn);
|
|
609
513
|
}
|
|
610
|
-
|
|
611
514
|
function runMount() {
|
|
612
515
|
if (scope.disposed || executed) {
|
|
613
516
|
return;
|
|
614
517
|
}
|
|
615
|
-
|
|
616
518
|
executed = true;
|
|
617
|
-
|
|
618
519
|
try {
|
|
619
520
|
const result = callback(createMountContext(registerCleanup));
|
|
620
521
|
applyCleanupResult(result, registerCleanup);
|
|
621
|
-
}
|
|
522
|
+
}
|
|
523
|
+
catch (error) {
|
|
622
524
|
// Unhandled mount errors shouldn't crash hydration, but we log them
|
|
623
525
|
console.error('[Zenith Runtime] Unhandled error during zenMount:', error);
|
|
624
526
|
}
|
|
625
|
-
|
|
626
527
|
registeredDisposer = registerScopeDisposer(scope, () => {
|
|
627
528
|
drainCleanupStack(cleanups);
|
|
628
529
|
});
|
|
629
530
|
}
|
|
630
|
-
|
|
631
531
|
queueWhenScopeReady(scope, runMount);
|
|
632
|
-
|
|
633
532
|
return function dispose() {
|
|
634
533
|
if (registeredDisposer) {
|
|
635
534
|
registeredDisposer();
|
|
636
|
-
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
637
537
|
drainCleanupStack(cleanups);
|
|
638
538
|
}
|
|
639
539
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenithbuild/runtime",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -29,14 +29,17 @@
|
|
|
29
29
|
},
|
|
30
30
|
"homepage": "https://github.com/zenithbuild/framework#readme",
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "
|
|
32
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
33
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
34
|
"test": "npm run build && NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.js",
|
|
34
35
|
"prepublishOnly": "npm run build"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
38
|
+
"@types/node": "latest",
|
|
37
39
|
"@jest/globals": "^30.2.0",
|
|
38
40
|
"jest": "^30.2.0",
|
|
39
|
-
"jest-environment-jsdom": "^30.2.0"
|
|
41
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
42
|
+
"typescript": "^5.7.3"
|
|
40
43
|
},
|
|
41
44
|
"private": false
|
|
42
45
|
}
|