@zenithbuild/cli 0.7.5 → 0.7.7

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 (68) hide show
  1. package/dist/adapters/adapter-netlify.js +0 -8
  2. package/dist/adapters/adapter-vercel.js +6 -14
  3. package/dist/adapters/copy-hosted-page-runtime.js +2 -1
  4. package/dist/build/hoisted-code-transforms.d.ts +4 -1
  5. package/dist/build/hoisted-code-transforms.js +5 -3
  6. package/dist/build/page-ir-normalization.d.ts +1 -1
  7. package/dist/build/page-ir-normalization.js +33 -3
  8. package/dist/build/page-loop.js +46 -2
  9. package/dist/dev-build-session/helpers.d.ts +29 -0
  10. package/dist/dev-build-session/helpers.js +223 -0
  11. package/dist/dev-build-session/session.d.ts +24 -0
  12. package/dist/dev-build-session/session.js +204 -0
  13. package/dist/dev-build-session/state.d.ts +37 -0
  14. package/dist/dev-build-session/state.js +17 -0
  15. package/dist/dev-build-session.d.ts +1 -24
  16. package/dist/dev-build-session.js +1 -434
  17. package/dist/dev-server/css-state.d.ts +7 -0
  18. package/dist/dev-server/css-state.js +92 -0
  19. package/dist/dev-server/not-found.d.ts +23 -0
  20. package/dist/dev-server/not-found.js +129 -0
  21. package/dist/dev-server/request-handler.d.ts +1 -0
  22. package/dist/dev-server/request-handler.js +376 -0
  23. package/dist/dev-server/route-check.d.ts +9 -0
  24. package/dist/dev-server/route-check.js +100 -0
  25. package/dist/dev-server/watcher.d.ts +5 -0
  26. package/dist/dev-server/watcher.js +216 -0
  27. package/dist/dev-server.js +123 -924
  28. package/dist/images/payload.js +4 -0
  29. package/dist/manifest.js +46 -1
  30. package/dist/preview/create-preview-server.d.ts +18 -0
  31. package/dist/preview/create-preview-server.js +71 -0
  32. package/dist/preview/manifest.d.ts +42 -0
  33. package/dist/preview/manifest.js +57 -0
  34. package/dist/preview/paths.d.ts +3 -0
  35. package/dist/preview/paths.js +38 -0
  36. package/dist/preview/payload.d.ts +6 -0
  37. package/dist/preview/payload.js +34 -0
  38. package/dist/preview/request-handler.d.ts +1 -0
  39. package/dist/preview/request-handler.js +300 -0
  40. package/dist/preview/server-runner.d.ts +49 -0
  41. package/dist/preview/server-runner.js +220 -0
  42. package/dist/preview/server-script-runner-template.d.ts +1 -0
  43. package/dist/preview/server-script-runner-template.js +425 -0
  44. package/dist/preview.d.ts +5 -112
  45. package/dist/preview.js +7 -1119
  46. package/dist/resource-response.d.ts +15 -0
  47. package/dist/resource-response.js +91 -2
  48. package/dist/server-contract/constants.d.ts +5 -0
  49. package/dist/server-contract/constants.js +5 -0
  50. package/dist/server-contract/export-validation.d.ts +5 -0
  51. package/dist/server-contract/export-validation.js +59 -0
  52. package/dist/server-contract/json-serializable.d.ts +1 -0
  53. package/dist/server-contract/json-serializable.js +52 -0
  54. package/dist/server-contract/resolve.d.ts +15 -0
  55. package/dist/server-contract/resolve.js +271 -0
  56. package/dist/server-contract/result-helpers.d.ts +51 -0
  57. package/dist/server-contract/result-helpers.js +59 -0
  58. package/dist/server-contract/route-result-validation.d.ts +2 -0
  59. package/dist/server-contract/route-result-validation.js +73 -0
  60. package/dist/server-contract/stage.d.ts +6 -0
  61. package/dist/server-contract/stage.js +22 -0
  62. package/dist/server-contract.d.ts +6 -62
  63. package/dist/server-contract.js +9 -493
  64. package/dist/server-middleware.d.ts +10 -0
  65. package/dist/server-middleware.js +30 -0
  66. package/dist/server-output.js +13 -1
  67. package/dist/server-runtime/node-server.js +25 -3
  68. package/package.json +3 -3
@@ -0,0 +1,216 @@
1
+ import { existsSync, watch } from 'node:fs';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { isAbsolute, relative, resolve } from 'node:path';
4
+ import { readChangeFingerprint } from '../dev-watch.js';
5
+ import { loadRouteSurfaceState } from '../preview.js';
6
+ export function createDevWatcher(options) {
7
+ const { watchRoots, resolvedOutDir, resolvedOutDirTmp, projectRoot, rebuildDebounceMs, queuedRebuildDebounceMs, buildSession, outDir, configuredBasePath, logger, startupProfile, state, syncCssStateFromBuild, broadcastEvent, trace } = options;
8
+ /** @type {import('fs').FSWatcher[]} */
9
+ let watchers = [];
10
+ let buildDebounce = null;
11
+ let queuedFiles = new Set();
12
+ const lastQueuedFingerprints = new Map();
13
+ let buildInFlight = false;
14
+ function isWithin(parent, child) {
15
+ const rel = relative(parent, child);
16
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
17
+ }
18
+ function toDisplayPath(absPath) {
19
+ const rel = relative(projectRoot, absPath);
20
+ if (rel === '')
21
+ return '.';
22
+ if (!rel.startsWith('..') && !isAbsolute(rel)) {
23
+ return rel;
24
+ }
25
+ return absPath;
26
+ }
27
+ function shouldIgnoreChange(absPath) {
28
+ if (isWithin(resolvedOutDir, absPath)) {
29
+ return true;
30
+ }
31
+ if (isWithin(resolvedOutDirTmp, absPath)) {
32
+ return true;
33
+ }
34
+ const rel = relative(projectRoot, absPath);
35
+ if (rel.startsWith('..') || isAbsolute(rel)) {
36
+ return false;
37
+ }
38
+ const segments = rel.split(/[\\/]+/g);
39
+ return segments.includes('node_modules')
40
+ || segments.includes('.git')
41
+ || segments.includes('.zenith')
42
+ || segments.includes('target')
43
+ || segments.includes('.turbo');
44
+ }
45
+ const triggerBuildDrain = (delayMs = rebuildDebounceMs) => {
46
+ if (buildDebounce !== null) {
47
+ clearTimeout(buildDebounce);
48
+ }
49
+ buildDebounce = setTimeout(() => {
50
+ buildDebounce = null;
51
+ void drainBuildQueue();
52
+ }, delayMs);
53
+ };
54
+ const drainBuildQueue = async () => {
55
+ if (buildInFlight) {
56
+ return;
57
+ }
58
+ const changedPaths = Array.from(queuedFiles);
59
+ const changed = changedPaths.map(toDisplayPath).sort();
60
+ if (changed.length === 0) {
61
+ return;
62
+ }
63
+ queuedFiles.clear();
64
+ buildInFlight = true;
65
+ const cycleBuildId = state.pendingBuildId + 1;
66
+ state.pendingBuildId = cycleBuildId;
67
+ state.buildStatus = 'building';
68
+ logger.build(`Rebuild (id=${cycleBuildId})`);
69
+ broadcastEvent('build_start', { buildId: cycleBuildId, changedFiles: changed });
70
+ const startTime = Date.now();
71
+ const previousCssAssetPath = state.currentCssAssetPath;
72
+ const previousCssContent = state.currentCssContent;
73
+ const onlyCss = changed.length > 0 && changed.every((filePath) => filePath.endsWith('.css'));
74
+ try {
75
+ const buildResult = await buildSession.build({ changedFiles: changedPaths, logger });
76
+ const cssReady = await syncCssStateFromBuild(buildResult, cycleBuildId);
77
+ if (!onlyCss) {
78
+ state.currentRouteState = await loadRouteSurfaceState(outDir, configuredBasePath);
79
+ }
80
+ const cssChanged = cssReady && (state.currentCssAssetPath !== previousCssAssetPath ||
81
+ state.currentCssContent !== previousCssContent);
82
+ state.buildId = cycleBuildId;
83
+ state.buildStatus = 'ok';
84
+ state.buildError = null;
85
+ state.lastBuildMs = Date.now();
86
+ state.durationMs = state.lastBuildMs - startTime;
87
+ logger.build(`Complete (id=${cycleBuildId}, ${state.durationMs}ms)`);
88
+ broadcastEvent('build_complete', {
89
+ buildId: cycleBuildId,
90
+ durationMs: state.durationMs,
91
+ status: state.buildStatus,
92
+ cssHref: state.currentCssHref,
93
+ changedFiles: changed
94
+ });
95
+ trace('state_snapshot', {
96
+ status: state.buildStatus,
97
+ buildId: cycleBuildId,
98
+ cssHref: state.currentCssHref,
99
+ durationMs: state.durationMs,
100
+ changedFiles: changed
101
+ });
102
+ if (cssChanged && state.currentCssHref.length > 0) {
103
+ logger.css(`ready (${state.currentCssHref})`);
104
+ logger.hmr(`css_update (buildId=${cycleBuildId})`);
105
+ broadcastEvent('css_update', { href: state.currentCssHref, changedFiles: changed });
106
+ }
107
+ if (!onlyCss) {
108
+ logger.hmr(`reload (buildId=${cycleBuildId})`);
109
+ broadcastEvent('reload', { changedFiles: changed });
110
+ }
111
+ else {
112
+ trace('css_only_update', {
113
+ buildId: cycleBuildId,
114
+ cssHref: state.currentCssHref,
115
+ cssChanged,
116
+ changedFiles: changed
117
+ });
118
+ }
119
+ }
120
+ catch (error) {
121
+ const fullError = error instanceof Error ? error.message : String(error);
122
+ state.buildStatus = 'error';
123
+ state.buildError = {
124
+ message: fullError.length > 10000
125
+ ? `${fullError.slice(0, 10000)}... (truncated)`
126
+ : fullError
127
+ };
128
+ state.lastBuildMs = Date.now();
129
+ state.durationMs = state.lastBuildMs - startTime;
130
+ logger.error('rebuild failed', {
131
+ hint: 'fix the error and save again',
132
+ error
133
+ });
134
+ broadcastEvent('build_error', {
135
+ buildId: cycleBuildId,
136
+ ...state.buildError,
137
+ changedFiles: changed
138
+ });
139
+ trace('state_snapshot', {
140
+ status: state.buildStatus,
141
+ buildId: state.buildId,
142
+ cssHref: state.currentCssHref,
143
+ durationMs: state.durationMs,
144
+ error: state.buildError
145
+ });
146
+ }
147
+ finally {
148
+ buildInFlight = false;
149
+ if (queuedFiles.size > 0) {
150
+ triggerBuildDrain(queuedRebuildDebounceMs);
151
+ }
152
+ }
153
+ };
154
+ function start() {
155
+ const watcherStartedAt = performance.now();
156
+ const roots = Array.from(watchRoots);
157
+ for (const root of roots) {
158
+ if (!existsSync(root))
159
+ continue;
160
+ try {
161
+ const watcher = watch(root, { recursive: true }, (_eventType, filename) => {
162
+ if (!filename) {
163
+ return;
164
+ }
165
+ const changedPath = resolve(root, String(filename));
166
+ if (shouldIgnoreChange(changedPath)) {
167
+ return;
168
+ }
169
+ void (async () => {
170
+ const fingerprint = await readChangeFingerprint(changedPath);
171
+ if (lastQueuedFingerprints.get(changedPath) === fingerprint) {
172
+ return;
173
+ }
174
+ lastQueuedFingerprints.set(changedPath, fingerprint);
175
+ queuedFiles.add(changedPath);
176
+ triggerBuildDrain();
177
+ })();
178
+ });
179
+ watchers.push(watcher);
180
+ }
181
+ catch {
182
+ // fs.watch recursive may not be supported on this platform/root
183
+ }
184
+ }
185
+ startupProfile.emit('watcher_ready', {
186
+ roots: roots.length,
187
+ activeWatchers: watchers.length,
188
+ durationMs: startupProfile.roundMs(performance.now() - watcherStartedAt)
189
+ });
190
+ }
191
+ function close() {
192
+ if (buildDebounce !== null) {
193
+ clearTimeout(buildDebounce);
194
+ buildDebounce = null;
195
+ }
196
+ for (const watcher of watchers) {
197
+ try {
198
+ watcher.close();
199
+ }
200
+ catch {
201
+ // ignore close errors
202
+ }
203
+ }
204
+ watchers = [];
205
+ queuedFiles.clear();
206
+ lastQueuedFingerprints.clear();
207
+ }
208
+ function activeWatcherCount() {
209
+ return watchers.length;
210
+ }
211
+ return {
212
+ start,
213
+ close,
214
+ activeWatcherCount
215
+ };
216
+ }