@zenithbuild/core 0.6.3 → 0.6.4

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.
Files changed (112) hide show
  1. package/CORE_CONTRACT.md +145 -0
  2. package/README.md +14 -29
  3. package/bin/zenith.js +89 -0
  4. package/package.json +40 -57
  5. package/src/config.js +136 -0
  6. package/src/core-template.js +30 -0
  7. package/src/errors.js +54 -0
  8. package/src/guards.js +61 -0
  9. package/src/hash.js +52 -0
  10. package/src/index.js +26 -0
  11. package/src/ir/index.js +1 -0
  12. package/src/order.js +69 -0
  13. package/src/path.js +131 -0
  14. package/src/schema.js +28 -0
  15. package/src/version.js +67 -0
  16. package/bin/zen-build.ts +0 -2
  17. package/bin/zen-dev.ts +0 -2
  18. package/bin/zen-preview.ts +0 -2
  19. package/bin/zenith.ts +0 -2
  20. package/cli/commands/add.ts +0 -37
  21. package/cli/commands/build.ts +0 -37
  22. package/cli/commands/create.ts +0 -702
  23. package/cli/commands/dev.ts +0 -388
  24. package/cli/commands/index.ts +0 -112
  25. package/cli/commands/preview.ts +0 -62
  26. package/cli/commands/remove.ts +0 -33
  27. package/cli/index.ts +0 -10
  28. package/cli/main.ts +0 -101
  29. package/cli/utils/branding.ts +0 -178
  30. package/cli/utils/content.ts +0 -112
  31. package/cli/utils/logger.ts +0 -46
  32. package/cli/utils/plugin-manager.ts +0 -114
  33. package/cli/utils/project.ts +0 -77
  34. package/compiler/README.md +0 -380
  35. package/compiler/build-analyzer.ts +0 -122
  36. package/compiler/css/index.ts +0 -317
  37. package/compiler/discovery/componentDiscovery.ts +0 -178
  38. package/compiler/discovery/layouts.ts +0 -70
  39. package/compiler/errors/compilerError.ts +0 -56
  40. package/compiler/finalize/finalizeOutput.ts +0 -192
  41. package/compiler/finalize/generateFinalBundle.ts +0 -82
  42. package/compiler/index.ts +0 -83
  43. package/compiler/ir/types.ts +0 -174
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/importTypes.ts +0 -78
  47. package/compiler/parse/parseImports.ts +0 -309
  48. package/compiler/parse/parseScript.ts +0 -46
  49. package/compiler/parse/parseTemplate.ts +0 -599
  50. package/compiler/parse/parseZenFile.ts +0 -66
  51. package/compiler/parse/scriptAnalysis.ts +0 -91
  52. package/compiler/parse/trackLoopContext.ts +0 -82
  53. package/compiler/runtime/dataExposure.ts +0 -317
  54. package/compiler/runtime/generateDOM.ts +0 -246
  55. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  56. package/compiler/runtime/hydration.ts +0 -309
  57. package/compiler/runtime/navigation.ts +0 -432
  58. package/compiler/runtime/thinRuntime.ts +0 -160
  59. package/compiler/runtime/transformIR.ts +0 -370
  60. package/compiler/runtime/wrapExpression.ts +0 -95
  61. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  62. package/compiler/spa-build.ts +0 -917
  63. package/compiler/ssg-build.ts +0 -422
  64. package/compiler/test/validate-test.ts +0 -104
  65. package/compiler/transform/classifyExpression.ts +0 -444
  66. package/compiler/transform/componentResolver.ts +0 -312
  67. package/compiler/transform/componentScriptTransformer.ts +0 -303
  68. package/compiler/transform/expressionTransformer.ts +0 -385
  69. package/compiler/transform/fragmentLowering.ts +0 -634
  70. package/compiler/transform/generateBindings.ts +0 -47
  71. package/compiler/transform/generateHTML.ts +0 -28
  72. package/compiler/transform/layoutProcessor.ts +0 -132
  73. package/compiler/transform/slotResolver.ts +0 -292
  74. package/compiler/transform/transformNode.ts +0 -126
  75. package/compiler/transform/transformTemplate.ts +0 -38
  76. package/compiler/validate/invariants.ts +0 -292
  77. package/compiler/validate/validateExpressions.ts +0 -168
  78. package/core/config/index.ts +0 -16
  79. package/core/config/loader.ts +0 -69
  80. package/core/config/types.ts +0 -89
  81. package/core/index.ts +0 -135
  82. package/core/lifecycle/index.ts +0 -49
  83. package/core/lifecycle/zen-mount.ts +0 -182
  84. package/core/lifecycle/zen-unmount.ts +0 -88
  85. package/core/plugins/index.ts +0 -7
  86. package/core/plugins/registry.ts +0 -81
  87. package/core/reactivity/index.ts +0 -54
  88. package/core/reactivity/tracking.ts +0 -167
  89. package/core/reactivity/zen-batch.ts +0 -57
  90. package/core/reactivity/zen-effect.ts +0 -139
  91. package/core/reactivity/zen-memo.ts +0 -146
  92. package/core/reactivity/zen-ref.ts +0 -52
  93. package/core/reactivity/zen-signal.ts +0 -121
  94. package/core/reactivity/zen-state.ts +0 -180
  95. package/core/reactivity/zen-untrack.ts +0 -44
  96. package/dist/cli.js +0 -11667
  97. package/dist/zen-build.js +0 -21442
  98. package/dist/zen-dev.js +0 -21442
  99. package/dist/zen-preview.js +0 -21442
  100. package/dist/zenith.js +0 -21442
  101. package/router/index.ts +0 -28
  102. package/router/manifest.ts +0 -314
  103. package/router/navigation/ZenLink.zen +0 -231
  104. package/router/navigation/index.ts +0 -78
  105. package/router/navigation/zen-link.ts +0 -584
  106. package/router/runtime.ts +0 -458
  107. package/router/types.ts +0 -168
  108. package/runtime/build.ts +0 -17
  109. package/runtime/bundle-generator.ts +0 -1257
  110. package/runtime/client-runtime.ts +0 -549
  111. package/runtime/serve.ts +0 -93
  112. package/tsconfig.json +0 -28
@@ -1,549 +0,0 @@
1
- /**
2
- * Zenith Client Runtime
3
- *
4
- * Shared runtime module served as /runtime.js in dev mode.
5
- * Includes:
6
- * - Reactivity primitives (signal, state, effect, memo)
7
- * - Lifecycle hooks (zenOnMount, zenOnUnmount)
8
- * - Event wiring
9
- * - Hydration functions
10
- *
11
- * This is a standalone module that can be imported/served separately
12
- * from page-specific code.
13
- */
14
-
15
- // ============================================
16
- // Dependency Tracking System
17
- // ============================================
18
-
19
- let currentEffect: any = null;
20
- const effectStack: any[] = [];
21
- let batchDepth = 0;
22
- const pendingEffects = new Set<any>();
23
-
24
- function pushContext(effect: any) {
25
- effectStack.push(currentEffect);
26
- currentEffect = effect;
27
- }
28
-
29
- function popContext() {
30
- currentEffect = effectStack.pop() || null;
31
- }
32
-
33
- function trackDependency(subscribers: Set<any>) {
34
- if (currentEffect) {
35
- subscribers.add(currentEffect);
36
- currentEffect.dependencies.add(subscribers);
37
- }
38
- }
39
-
40
- function notifySubscribers(subscribers: Set<any>) {
41
- const effects = [...subscribers];
42
- for (const effect of effects) {
43
- if (batchDepth > 0) {
44
- pendingEffects.add(effect);
45
- } else {
46
- effect.run();
47
- }
48
- }
49
- }
50
-
51
- function cleanupEffect(effect: any) {
52
- for (const deps of effect.dependencies) {
53
- deps.delete(effect);
54
- }
55
- effect.dependencies.clear();
56
- }
57
-
58
- // ============================================
59
- // zenSignal - Atomic reactive value
60
- // ============================================
61
-
62
- export function zenSignal<T>(initialValue: T): (newValue?: T) => T {
63
- let value = initialValue;
64
- const subscribers = new Set<any>();
65
-
66
- function signal(newValue?: T): T {
67
- if (arguments.length === 0) {
68
- trackDependency(subscribers);
69
- return value;
70
- }
71
- if (newValue !== value) {
72
- value = newValue as T;
73
- notifySubscribers(subscribers);
74
- }
75
- return value;
76
- }
77
-
78
- return signal;
79
- }
80
-
81
- // ============================================
82
- // zenState - Deep reactive object with Proxy
83
- // ============================================
84
-
85
- export function zenState<T extends object>(initialObj: T): T {
86
- const subscribers = new Map<string, Set<any>>();
87
-
88
- function getSubscribers(path: string): Set<any> {
89
- if (!subscribers.has(path)) {
90
- subscribers.set(path, new Set());
91
- }
92
- return subscribers.get(path)!;
93
- }
94
-
95
- function createProxy(obj: any, parentPath: string = ''): any {
96
- if (obj === null || typeof obj !== 'object') {
97
- return obj;
98
- }
99
-
100
- return new Proxy(obj, {
101
- get(target, prop) {
102
- if (typeof prop === 'symbol') return target[prop];
103
-
104
- const path = parentPath ? `${parentPath}.${String(prop)}` : String(prop);
105
- trackDependency(getSubscribers(path));
106
-
107
- const value = target[prop];
108
- if (value !== null && typeof value === 'object') {
109
- return createProxy(value, path);
110
- }
111
- return value;
112
- },
113
-
114
- set(target, prop, newValue) {
115
- if (typeof prop === 'symbol') {
116
- target[prop] = newValue;
117
- return true;
118
- }
119
-
120
- const path = parentPath ? `${parentPath}.${String(prop)}` : String(prop);
121
- const oldValue = target[prop];
122
-
123
- if (oldValue !== newValue) {
124
- target[prop] = newValue;
125
-
126
- // Notify this path
127
- const subs = subscribers.get(path);
128
- if (subs) notifySubscribers(subs);
129
-
130
- // Notify parent paths
131
- const parts = path.split('.');
132
- for (let i = parts.length - 1; i >= 0; i--) {
133
- const parentPath = parts.slice(0, i).join('.');
134
- if (parentPath) {
135
- const parentSubs = subscribers.get(parentPath);
136
- if (parentSubs) notifySubscribers(parentSubs);
137
- }
138
- }
139
- }
140
- return true;
141
- }
142
- });
143
- }
144
-
145
- return createProxy(initialObj);
146
- }
147
-
148
- // ============================================
149
- // zenEffect - Reactive effect
150
- // ============================================
151
-
152
- export function zenEffect(fn: () => void | (() => void)): () => void {
153
- let cleanup: (() => void) | void;
154
-
155
- const effect = {
156
- dependencies: new Set<Set<any>>(),
157
- run() {
158
- cleanupEffect(effect);
159
- pushContext(effect);
160
- try {
161
- if (cleanup) cleanup();
162
- cleanup = fn();
163
- } finally {
164
- popContext();
165
- }
166
- }
167
- };
168
-
169
- effect.run();
170
-
171
- return () => {
172
- cleanupEffect(effect);
173
- if (cleanup) cleanup();
174
- };
175
- }
176
-
177
- // ============================================
178
- // zenMemo - Computed/derived value
179
- // ============================================
180
-
181
- export function zenMemo<T>(fn: () => T): () => T {
182
- let value: T;
183
- let dirty = true;
184
- const subscribers = new Set<any>();
185
-
186
- const effect = {
187
- dependencies: new Set<Set<any>>(),
188
- run() {
189
- cleanupEffect(effect);
190
- pushContext(effect);
191
- try {
192
- value = fn();
193
- dirty = false;
194
- notifySubscribers(subscribers);
195
- } finally {
196
- popContext();
197
- }
198
- }
199
- };
200
-
201
- return () => {
202
- trackDependency(subscribers);
203
- if (dirty) {
204
- effect.run();
205
- }
206
- return value;
207
- };
208
- }
209
-
210
- // ============================================
211
- // zenRef - Non-reactive mutable container
212
- // ============================================
213
-
214
- export function zenRef<T>(initialValue?: T): { current: T | null } {
215
- return { current: initialValue !== undefined ? initialValue : null };
216
- }
217
-
218
- // ============================================
219
- // zenBatch - Batch updates
220
- // ============================================
221
-
222
- export function zenBatch(fn: () => void): void {
223
- batchDepth++;
224
- try {
225
- fn();
226
- } finally {
227
- batchDepth--;
228
- if (batchDepth === 0) {
229
- const effects = [...pendingEffects];
230
- pendingEffects.clear();
231
- for (const effect of effects) {
232
- effect.run();
233
- }
234
- }
235
- }
236
- }
237
-
238
- // ============================================
239
- // zenUntrack - Read without tracking
240
- // ============================================
241
-
242
- export function zenUntrack<T>(fn: () => T): T {
243
- const prevEffect = currentEffect;
244
- currentEffect = null;
245
- try {
246
- return fn();
247
- } finally {
248
- currentEffect = prevEffect;
249
- }
250
- }
251
-
252
- // ============================================
253
- // Lifecycle Hooks
254
- // ============================================
255
-
256
- const mountCallbacks: Array<() => void | (() => void)> = [];
257
- const unmountCallbacks: Array<() => void> = [];
258
- let isMounted = false;
259
-
260
- export function zenOnMount(fn: () => void | (() => void)): void {
261
- if (isMounted) {
262
- const cleanup = fn();
263
- if (typeof cleanup === 'function') {
264
- unmountCallbacks.push(cleanup);
265
- }
266
- } else {
267
- mountCallbacks.push(fn);
268
- }
269
- }
270
-
271
- export function zenOnUnmount(fn: () => void): void {
272
- unmountCallbacks.push(fn);
273
- }
274
-
275
- export function triggerMount(): void {
276
- isMounted = true;
277
- for (const cb of mountCallbacks) {
278
- const cleanup = cb();
279
- if (typeof cleanup === 'function') {
280
- unmountCallbacks.push(cleanup);
281
- }
282
- }
283
- mountCallbacks.length = 0;
284
- }
285
-
286
- export function triggerUnmount(): void {
287
- isMounted = false;
288
- for (const cb of unmountCallbacks) {
289
- try { cb(); } catch (e) { console.error('[Zenith] Unmount error:', e); }
290
- }
291
- unmountCallbacks.length = 0;
292
- }
293
-
294
- // ============================================
295
- // Expression Registry
296
- // ============================================
297
-
298
- const expressionRegistry = new Map<string, (state: any) => any>();
299
-
300
- export function registerExpression(id: string, fn: (state: any) => any): void {
301
- expressionRegistry.set(id, fn);
302
- }
303
-
304
- export function getExpression(id: string): ((state: any) => any) | undefined {
305
- return expressionRegistry.get(id);
306
- }
307
-
308
- // ============================================
309
- // Hydration Functions
310
- // ============================================
311
-
312
- const bindings: Array<{ node: Element; type: string; expressionId: string; attributeName?: string }> = [];
313
-
314
- export function hydrate(state: any, container?: Element | Document): void {
315
- const root = container || document;
316
-
317
- // Clear existing bindings
318
- bindings.length = 0;
319
-
320
- // Find all text expression placeholders
321
- const textPlaceholders = root.querySelectorAll('[data-zen-text]');
322
- textPlaceholders.forEach((node) => {
323
- const expressionId = node.getAttribute('data-zen-text');
324
- if (!expressionId) return;
325
-
326
- bindings.push({ node: node as Element, type: 'text', expressionId });
327
- updateTextBinding(node as Element, expressionId, state);
328
- });
329
-
330
- // Find attribute bindings
331
- const attrSelectors = ['class', 'style', 'src', 'href', 'disabled', 'checked'];
332
- for (const attr of attrSelectors) {
333
- const attrPlaceholders = root.querySelectorAll(`[data-zen-attr-${attr}]`);
334
- attrPlaceholders.forEach((node) => {
335
- const expressionId = node.getAttribute(`data-zen-attr-${attr}`);
336
- if (!expressionId) return;
337
-
338
- bindings.push({ node: node as Element, type: 'attribute', expressionId, attributeName: attr });
339
- updateAttributeBinding(node as Element, attr, expressionId, state);
340
- });
341
- }
342
-
343
- // Bind event handlers
344
- bindEvents(root);
345
-
346
- // Trigger mount
347
- triggerMount();
348
- }
349
-
350
- function updateTextBinding(node: Element, expressionId: string, state: any): void {
351
- const expression = expressionRegistry.get(expressionId);
352
- if (!expression) {
353
- console.warn(`[Zenith] Expression ${expressionId} not found`);
354
- return;
355
- }
356
-
357
- try {
358
- const result = expression(state);
359
- if (result === null || result === undefined || result === false) {
360
- node.textContent = '';
361
- } else if (typeof result === 'string') {
362
- if (result.trim().startsWith('<') && result.trim().endsWith('>')) {
363
- node.innerHTML = result;
364
- } else {
365
- node.textContent = result;
366
- }
367
- } else if (result instanceof Node) {
368
- node.innerHTML = '';
369
- node.appendChild(result);
370
- } else if (Array.isArray(result)) {
371
- node.innerHTML = '';
372
- const fragment = document.createDocumentFragment();
373
- result.flat(Infinity).forEach(item => {
374
- if (item instanceof Node) fragment.appendChild(item);
375
- else if (item != null && item !== false) fragment.appendChild(document.createTextNode(String(item)));
376
- });
377
- node.appendChild(fragment);
378
- } else {
379
- node.textContent = String(result);
380
- }
381
- } catch (error) {
382
- console.error(`[Zenith] Error evaluating expression ${expressionId}:`, error);
383
- }
384
- }
385
-
386
- function updateAttributeBinding(element: Element, attrName: string, expressionId: string, state: any): void {
387
- const expression = expressionRegistry.get(expressionId);
388
- if (!expression) return;
389
-
390
- try {
391
- const result = expression(state);
392
-
393
- if (attrName === 'class' || attrName === 'className') {
394
- (element as HTMLElement).className = String(result ?? '');
395
- } else if (attrName === 'style' && typeof result === 'object') {
396
- const styleStr = Object.entries(result).map(([k, v]) => `${k}: ${v}`).join('; ');
397
- element.setAttribute('style', styleStr);
398
- } else if (['disabled', 'checked', 'readonly'].includes(attrName)) {
399
- if (result) {
400
- element.setAttribute(attrName, '');
401
- } else {
402
- element.removeAttribute(attrName);
403
- }
404
- } else {
405
- if (result === null || result === undefined || result === false) {
406
- element.removeAttribute(attrName);
407
- } else {
408
- element.setAttribute(attrName, String(result));
409
- }
410
- }
411
- } catch (error) {
412
- console.error(`[Zenith] Error updating attribute ${attrName}:`, error);
413
- }
414
- }
415
-
416
- export function update(state: any): void {
417
- for (const binding of bindings) {
418
- if (binding.type === 'text') {
419
- updateTextBinding(binding.node, binding.expressionId, state);
420
- } else if (binding.type === 'attribute' && binding.attributeName) {
421
- updateAttributeBinding(binding.node, binding.attributeName, binding.expressionId, state);
422
- }
423
- }
424
- }
425
-
426
- export function bindEvents(container: Element | Document): void {
427
- const eventTypes = ['click', 'change', 'input', 'submit', 'focus', 'blur', 'keyup', 'keydown'];
428
-
429
- for (const eventType of eventTypes) {
430
- const elements = container.querySelectorAll(`[data-zen-${eventType}]`);
431
-
432
- elements.forEach((element) => {
433
- const handlerName = element.getAttribute(`data-zen-${eventType}`);
434
- if (!handlerName) return;
435
-
436
- // Remove existing handler if any
437
- const handlerKey = `__zen_${eventType}_handler`;
438
- const existingHandler = (element as any)[handlerKey];
439
- if (existingHandler) {
440
- element.removeEventListener(eventType, existingHandler);
441
- }
442
-
443
- // Create new handler
444
- const handler = (event: Event) => {
445
- try {
446
- // Try window first, then expression registry
447
- let handlerFunc = (window as any)[handlerName];
448
- if (typeof handlerFunc !== 'function') {
449
- handlerFunc = (window as any).__ZENITH_EXPRESSIONS__?.get(handlerName);
450
- }
451
-
452
- if (typeof handlerFunc === 'function') {
453
- handlerFunc(event, element);
454
- } else {
455
- console.warn(`[Zenith] Event handler "${handlerName}" not found`);
456
- }
457
- } catch (error) {
458
- console.error(`[Zenith] Error executing handler "${handlerName}":`, error);
459
- }
460
- };
461
-
462
- (element as any)[handlerKey] = handler;
463
- element.addEventListener(eventType, handler);
464
- });
465
- }
466
- }
467
-
468
- export function cleanup(container?: Element | Document): void {
469
- const root = container || document;
470
- const eventTypes = ['click', 'change', 'input', 'submit', 'focus', 'blur', 'keyup', 'keydown'];
471
-
472
- for (const eventType of eventTypes) {
473
- const elements = root.querySelectorAll(`[data-zen-${eventType}]`);
474
- elements.forEach((element) => {
475
- const handlerKey = `__zen_${eventType}_handler`;
476
- const handler = (element as any)[handlerKey];
477
- if (handler) {
478
- element.removeEventListener(eventType, handler);
479
- delete (element as any)[handlerKey];
480
- }
481
- });
482
- }
483
-
484
- bindings.length = 0;
485
- triggerUnmount();
486
- }
487
-
488
- // ============================================
489
- // Browser Globals Setup
490
- // ============================================
491
-
492
- export function setupGlobals(): void {
493
- if (typeof window === 'undefined') return;
494
-
495
- const w = window as any;
496
-
497
- // Zenith namespace
498
- w.__zenith = {
499
- signal: zenSignal,
500
- state: zenState,
501
- effect: zenEffect,
502
- memo: zenMemo,
503
- ref: zenRef,
504
- batch: zenBatch,
505
- untrack: zenUntrack,
506
- onMount: zenOnMount,
507
- onUnmount: zenOnUnmount,
508
- triggerMount,
509
- triggerUnmount
510
- };
511
-
512
- // Expression registry
513
- w.__ZENITH_EXPRESSIONS__ = expressionRegistry;
514
-
515
- // Hydration functions
516
- w.__zenith_hydrate = hydrate;
517
- w.__zenith_update = update;
518
- w.__zenith_bindEvents = bindEvents;
519
- w.__zenith_cleanup = cleanup;
520
- w.zenithHydrate = hydrate;
521
- w.zenithUpdate = update;
522
- w.zenithBindEvents = bindEvents;
523
- w.zenithCleanup = cleanup;
524
-
525
- // Direct primitives
526
- w.zenSignal = zenSignal;
527
- w.zenState = zenState;
528
- w.zenEffect = zenEffect;
529
- w.zenMemo = zenMemo;
530
- w.zenRef = zenRef;
531
- w.zenBatch = zenBatch;
532
- w.zenUntrack = zenUntrack;
533
- w.zenOnMount = zenOnMount;
534
- w.zenOnUnmount = zenOnUnmount;
535
-
536
- // Short aliases
537
- w.signal = zenSignal;
538
- w.state = zenState;
539
- w.effect = zenEffect;
540
- w.memo = zenMemo;
541
- w.ref = zenRef;
542
- w.batch = zenBatch;
543
- w.untrack = zenUntrack;
544
- w.onMount = zenOnMount;
545
- w.onUnmount = zenOnUnmount;
546
- }
547
-
548
- // Auto-setup globals on import
549
- setupGlobals();
package/runtime/serve.ts DELETED
@@ -1,93 +0,0 @@
1
- /**
2
- * Zenith Development Server
3
- *
4
- * SPA-compatible server that:
5
- * - Serves static assets directly (js, css, ico, images)
6
- * - Serves index.html for all other routes (SPA fallback)
7
- *
8
- * This enables client-side routing to work on:
9
- * - Direct URL entry
10
- * - Hard refresh
11
- * - Back/forward navigation
12
- */
13
-
14
- import { serve } from "bun"
15
- import path from "path"
16
-
17
- const distDir = path.resolve(import.meta.dir, "..", "app", "dist")
18
-
19
- // File extensions that should be served as static assets
20
- const STATIC_EXTENSIONS = new Set([
21
- ".js",
22
- ".css",
23
- ".ico",
24
- ".png",
25
- ".jpg",
26
- ".jpeg",
27
- ".gif",
28
- ".svg",
29
- ".webp",
30
- ".woff",
31
- ".woff2",
32
- ".ttf",
33
- ".eot",
34
- ".json",
35
- ".map"
36
- ])
37
-
38
- serve({
39
- port: 3000,
40
-
41
- async fetch(req) {
42
- const url = new URL(req.url)
43
- const pathname = url.pathname
44
-
45
- // Get file extension
46
- const ext = path.extname(pathname).toLowerCase()
47
-
48
- // Check if this is a static asset request
49
- if (STATIC_EXTENSIONS.has(ext)) {
50
- const filePath = path.join(distDir, pathname)
51
- const file = Bun.file(filePath)
52
-
53
- // Check if file exists
54
- if (await file.exists()) {
55
- return new Response(file)
56
- }
57
-
58
- // Static file not found
59
- return new Response("Not found", { status: 404 })
60
- }
61
-
62
- // For all other routes, serve index.html (SPA fallback)
63
- const indexPath = path.join(distDir, "index.html")
64
- const indexFile = Bun.file(indexPath)
65
-
66
- if (await indexFile.exists()) {
67
- return new Response(indexFile, {
68
- headers: {
69
- "Content-Type": "text/html; charset=utf-8"
70
- }
71
- })
72
- }
73
-
74
- // No index.html found - likely need to run build first
75
- return new Response(
76
- `<html>
77
- <head><title>Zenith - Build Required</title></head>
78
- <body style="font-family: system-ui; padding: 2rem; text-align: center;">
79
- <h1>Build Required</h1>
80
- <p>Run <code>bun runtime/build.ts</code> first to compile the pages.</p>
81
- </body>
82
- </html>`,
83
- {
84
- status: 500,
85
- headers: { "Content-Type": "text/html; charset=utf-8" }
86
- }
87
- )
88
- }
89
- })
90
-
91
- console.log("🚀 Zenith dev server running at http://localhost:3000")
92
- console.log(" SPA mode: All routes serve index.html")
93
-
package/tsconfig.json DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Environment setup & latest features
4
- "lib": [
5
- "DOM",
6
- "ESNext"
7
- ],
8
- "target": "ESNext",
9
- "module": "ESNext",
10
- "moduleDetection": "force",
11
- "allowJs": true,
12
- // Bundler mode
13
- "moduleResolution": "bundler",
14
- "allowImportingTsExtensions": true,
15
- "verbatimModuleSyntax": true,
16
- "noEmit": true,
17
- // Best practices
18
- "strict": true,
19
- "skipLibCheck": true,
20
- "noFallthroughCasesInSwitch": true,
21
- "noUncheckedIndexedAccess": true,
22
- "noImplicitOverride": true,
23
- // Some stricter flags (disabled by default)
24
- "noUnusedLocals": false,
25
- "noUnusedParameters": false,
26
- "noPropertyAccessFromIndexSignature": false
27
- }
28
- }