evolit 0.1.0-alpha.14 → 0.1.0-alpha.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolit",
3
- "version": "0.1.0-alpha.14",
3
+ "version": "0.1.0-alpha.16",
4
4
  "description": "A convention-driven application framework for LitSX and web components.",
5
5
  "type": "module",
6
6
  "packageManager": "yarn@4.10.3",
package/src/cli.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
5
  import { scaffoldSite } from "./scaffold.js";
6
+ import { terminal } from "./terminal.js";
6
7
 
7
8
  function parseArguments(argv) {
8
9
  const [command, ...rest] = argv;
@@ -24,9 +25,9 @@ function parseArguments(argv) {
24
25
  }
25
26
 
26
27
  function printUsage() {
27
- console.log("Usage: evolit <directory>");
28
- console.log(" evolit init <directory>");
29
- console.log(" evolit <dev|build|start> [--port 3000]");
28
+ console.log(`${terminal.bold("Usage:")} evolit <directory>`);
29
+ console.log(` evolit ${terminal.cyan("init")} <directory>`);
30
+ console.log(` evolit ${terminal.cyan("<dev|build|start>")} [--port 3000]`);
30
31
  }
31
32
 
32
33
  async function createSite(projectRoot, targetDirectory) {
@@ -35,7 +36,7 @@ async function createSite(projectRoot, targetDirectory) {
35
36
  }
36
37
 
37
38
  const createdDirectory = await scaffoldSite(path.resolve(projectRoot, targetDirectory));
38
- console.log(`Created evolit site: ${createdDirectory}`);
39
+ console.log(`${terminal.green("✓")} Created evolit site: ${terminal.cyan(createdDirectory)}`);
39
40
  }
40
41
 
41
42
  async function run() {
@@ -55,23 +56,25 @@ async function run() {
55
56
  if (command === "build") {
56
57
  const { buildProject } = await import("./build.js");
57
58
  const manifestPath = await buildProject(projectRoot);
58
- console.log(`Built evolit app: ${path.relative(projectRoot, manifestPath)}`);
59
+ console.log(`${terminal.green("✓")} Built Evolit app: ${terminal.cyan(path.relative(projectRoot, manifestPath))}`);
59
60
  return;
60
61
  }
61
62
 
62
63
  if (command === "start") {
63
64
  const { createStartServer } = await import("./server.js");
65
+ console.log(`${terminal.cyan("▲")} ${terminal.bold("Evolit")} ${terminal.cyan("start")}`);
64
66
  const server = await createStartServer(projectRoot, options);
65
67
  await server.listen();
66
- console.log(`evolit start listening on http://localhost:${server.port}`);
68
+ console.log(`${terminal.green("✓")} Ready on ${terminal.cyan(`http://localhost:${server.port}`)}`);
67
69
  return;
68
70
  }
69
71
 
70
72
  if (command === "dev") {
71
73
  const { createDevServer } = await import("./server.js");
74
+ console.log(`${terminal.cyan("▲")} ${terminal.bold("Evolit")} ${terminal.cyan("dev")}`);
72
75
  const server = await createDevServer(projectRoot, options);
73
76
  await server.listen();
74
- console.log(`evolit dev listening on http://localhost:${server.port}`);
77
+ console.log(`${terminal.green("✓")} Ready on ${terminal.cyan(`http://localhost:${server.port}`)}`);
75
78
  return;
76
79
  }
77
80
 
@@ -79,6 +82,8 @@ async function run() {
79
82
  }
80
83
 
81
84
  run().catch((error) => {
82
- console.error(error instanceof Error ? error.stack ?? error.message : String(error));
85
+ console.error(
86
+ `${terminal.red("[evolit]")} ${terminal.red("✖")} ${error instanceof Error ? error.stack ?? error.message : String(error)}`,
87
+ );
83
88
  process.exitCode = 1;
84
89
  });
@@ -36,6 +36,23 @@ const sharedRuntimeBuildCache = new Map();
36
36
  const clientVendorSpecifierCache = new Map();
37
37
  const clientModuleMetadataCache = new Map();
38
38
 
39
+ export function resetDevelopmentAssetCaches(projectRoot) {
40
+ const normalizedProjectRoot = path.resolve(projectRoot);
41
+ const developmentPrefix = `${normalizedProjectRoot}::development::`;
42
+
43
+ for (const cache of [
44
+ sharedRuntimeBuildCache,
45
+ clientVendorSpecifierCache,
46
+ clientModuleMetadataCache,
47
+ ]) {
48
+ for (const key of cache.keys()) {
49
+ if (key.startsWith(developmentPrefix)) {
50
+ cache.delete(key);
51
+ }
52
+ }
53
+ }
54
+ }
55
+
39
56
  function isBareSpecifier(specifier) {
40
57
  return (
41
58
  typeof specifier === "string" &&
package/src/compiler.js CHANGED
@@ -25,6 +25,7 @@ const developmentGraphCache = new Map();
25
25
  const developmentGraphDependencies = new Map();
26
26
  const developmentModuleNamespaceCache = new Map();
27
27
  const developmentGraphVersions = new Map();
28
+ const developmentExternalImportWarnings = new Set();
28
29
 
29
30
  function isRelativeSpecifier(specifier) {
30
31
  return specifier.startsWith("./") || specifier.startsWith("../");
@@ -60,6 +61,29 @@ function isStyleAssetPath(filePath) {
60
61
  return filePath.endsWith(".css");
61
62
  }
62
63
 
64
+ function isPathOutsideProject(projectRoot, filePath) {
65
+ const relativePath = path.relative(projectRoot, filePath);
66
+ return (
67
+ relativePath === ".." ||
68
+ relativePath.startsWith(`..${path.sep}`) ||
69
+ path.isAbsolute(relativePath)
70
+ );
71
+ }
72
+
73
+ function reportDevelopmentExternalImport(projectRoot, sourcePath, resolvedImportPath, onDevelopmentEvent) {
74
+ const warningKey = `${path.resolve(projectRoot)}::${sourcePath}::${resolvedImportPath}`;
75
+ if (developmentExternalImportWarnings.has(warningKey)) {
76
+ return;
77
+ }
78
+
79
+ developmentExternalImportWarnings.add(warningKey);
80
+ onDevelopmentEvent?.({
81
+ type: "external-import",
82
+ sourcePath,
83
+ resolvedImportPath,
84
+ });
85
+ }
86
+
63
87
  function createStaticAssetStubSource(relativeAssetPath, mode, target = "server", staticAssetPublicUrls = null) {
64
88
  const normalizedAssetPath = relativeAssetPath.split(path.sep).join("/");
65
89
  if (normalizedAssetPath.endsWith(".css")) {
@@ -112,7 +136,7 @@ function getTypedOutputRoot(projectRoot, mode, target = "server") {
112
136
  }
113
137
 
114
138
  function toOutputPath(projectRoot, outputRoot, sourcePath) {
115
- const relativePath = path.relative(projectRoot, sourcePath);
139
+ const relativePath = toOutputRelativePath(projectRoot, sourcePath);
116
140
  const extension = path.extname(relativePath);
117
141
  if (!extension) {
118
142
  return path.join(outputRoot, `${relativePath}.mjs`);
@@ -124,6 +148,22 @@ function toOutputPath(projectRoot, outputRoot, sourcePath) {
124
148
  );
125
149
  }
126
150
 
151
+ function toOutputRelativePath(projectRoot, sourcePath) {
152
+ const relativePath = path.relative(projectRoot, sourcePath);
153
+ const isOutsideProject =
154
+ relativePath === ".." ||
155
+ relativePath.startsWith(`..${path.sep}`) ||
156
+ path.isAbsolute(relativePath);
157
+ if (!isOutsideProject) {
158
+ return relativePath;
159
+ }
160
+
161
+ return path.join(
162
+ "__external__",
163
+ ...relativePath.split(path.sep).map((segment) => segment === ".." ? "__up__" : segment),
164
+ );
165
+ }
166
+
127
167
  async function rewriteRelativeSpecifiers({
128
168
  projectRoot,
129
169
  outputRoot,
@@ -138,6 +178,7 @@ async function rewriteRelativeSpecifiers({
138
178
  sourceMaps,
139
179
  outputPath,
140
180
  inputSourceMap,
181
+ onDevelopmentEvent,
141
182
  }) {
142
183
  const magicSource = new MagicString(code);
143
184
  let didRewrite = false;
@@ -169,13 +210,17 @@ async function rewriteRelativeSpecifiers({
169
210
  continue;
170
211
  }
171
212
 
213
+ if (mode === "development" && isPathOutsideProject(projectRoot, resolvedImportPath)) {
214
+ reportDevelopmentExternalImport(projectRoot, sourcePath, resolvedImportPath, onDevelopmentEvent);
215
+ }
216
+
172
217
  const importerOutputPath = toOutputPath(projectRoot, outputRoot, sourcePath);
173
218
  let compiledImportPath = null;
174
219
 
175
220
  if (shouldCompileModule(resolvedImportPath)) {
176
221
  compiledImportPath = await compileModule(resolvedImportPath);
177
222
  } else if (isStaticAssetPath(resolvedImportPath)) {
178
- const relativeAssetPath = path.relative(projectRoot, resolvedImportPath);
223
+ const relativeAssetPath = toOutputRelativePath(projectRoot, resolvedImportPath);
179
224
  const assetOutputPath = path.join(outputRoot, relativeAssetPath);
180
225
  const stubOutputPath = `${assetOutputPath}.mjs`;
181
226
 
@@ -293,6 +338,14 @@ export function invalidateDevelopmentCompilationCache(projectRoot, changedPaths
293
338
  : null;
294
339
  let invalidated = false;
295
340
 
341
+ if (normalizedChangedPaths == null) {
342
+ for (const warningKey of developmentExternalImportWarnings) {
343
+ if (warningKey.startsWith(prefix)) {
344
+ developmentExternalImportWarnings.delete(warningKey);
345
+ }
346
+ }
347
+ }
348
+
296
349
  for (const key of developmentGraphCache.keys()) {
297
350
  if (!key.startsWith(prefix)) {
298
351
  continue;
@@ -323,6 +376,7 @@ async function compileModuleGraphUncached(entryPath, options = {}) {
323
376
  ssr = false,
324
377
  target = "server",
325
378
  staticAssetPublicUrls = null,
379
+ onDevelopmentEvent,
326
380
  } = options;
327
381
 
328
382
  const outputRoot = getTypedOutputRoot(projectRoot, mode, target);
@@ -361,6 +415,7 @@ async function compileModuleGraphUncached(entryPath, options = {}) {
361
415
  sourceMaps,
362
416
  outputPath,
363
417
  inputSourceMap: transformed.map ?? null,
418
+ onDevelopmentEvent,
364
419
  });
365
420
 
366
421
  await fs.writeFile(outputPath, rewritten.code, "utf8");
@@ -10,17 +10,20 @@ import {
10
10
  createAssetResolver,
11
11
  createHydrationBootstrap,
12
12
  createStaticAssetPublicUrlMap,
13
+ buildSharedVendorRuntime,
13
14
  emitBundledClientAssetsWithState,
14
15
  getAssetByPublicUrl,
15
16
  getSharedOutputRoot,
16
17
  normalizeHydrationDataForClient,
17
18
  normalizeClientAssetManifest,
19
+ resetDevelopmentAssetCaches,
18
20
  resolveRouteClientImports,
19
21
  resolveSharedVendorModuleUrl,
20
22
  resolveBrowserPackageAssetFilePath,
21
23
  rewriteHydrationDataScript,
22
24
  } from "./client-assets.js";
23
25
  import { loadEvolitConfig } from "./config.js";
26
+ import { DEV_DIRECTORY, INTERNAL_DIRECTORY } from "./constants.js";
24
27
  import { createRouteResolver } from "./render.js";
25
28
  import {
26
29
  createCachedRouteResponse,
@@ -212,7 +215,14 @@ export function createResponseCacheController({ responseCacheRuntime }) {
212
215
  };
213
216
  }
214
217
 
215
- export async function createRequestRenderer({ projectRoot, mode, assetManifest, routeResolver, responseCacheRuntime }) {
218
+ export async function createRequestRenderer({
219
+ projectRoot,
220
+ mode,
221
+ assetManifest,
222
+ routeResolver,
223
+ responseCacheRuntime,
224
+ onDevelopmentEvent,
225
+ }) {
216
226
  let currentAssetManifest = normalizeClientAssetManifest(assetManifest);
217
227
  let currentAssetResolver = createAssetResolver(projectRoot, {
218
228
  assetManifest: currentAssetManifest,
@@ -241,11 +251,18 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
241
251
  return nextWork;
242
252
  }
243
253
 
254
+ function reportDevelopmentEvent(event) {
255
+ if (mode === "development" && typeof onDevelopmentEvent === "function") {
256
+ onDevelopmentEvent(event);
257
+ }
258
+ }
259
+
244
260
  function getDevClientModuleKey(clientModule) {
245
261
  return path.resolve(projectRoot, clientModule);
246
262
  }
247
263
  async function createFrameworkRouteResolver() {
248
264
  return createRouteResolver(projectRoot, mode, {
265
+ onDevelopmentEvent,
249
266
  getStaticAssetPublicUrls() {
250
267
  return createStaticAssetPublicUrlMap(currentAssetManifest);
251
268
  },
@@ -338,6 +355,12 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
338
355
  }
339
356
  }
340
357
 
358
+ reportDevelopmentEvent({
359
+ type: "invalidated",
360
+ changedPathCount: normalizedChangedPaths?.size ?? null,
361
+ affectedClientEntryCount: affectedClientModules.size,
362
+ });
363
+
341
364
  if (usesFrameworkRouteResolver) {
342
365
  effectiveRouteResolver = await createFrameworkRouteResolver();
343
366
  }
@@ -360,6 +383,7 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
360
383
  mode,
361
384
  sourceMaps: false,
362
385
  target: "client",
386
+ onDevelopmentEvent,
363
387
  });
364
388
  }
365
389
  return;
@@ -378,6 +402,7 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
378
402
  mode,
379
403
  sourceMaps: true,
380
404
  target: "client",
405
+ onDevelopmentEvent,
381
406
  });
382
407
  devPreparedClientModules.add(clientModuleKey);
383
408
  devClientModuleDependencies.set(
@@ -392,10 +417,16 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
392
417
 
393
418
  if (!discoveredClientEntry && currentAssetManifest) {
394
419
  developmentMetrics.clientArtifactCacheHits += 1;
420
+ reportDevelopmentEvent({ type: "client-assets-cache-hit" });
395
421
  return;
396
422
  }
397
423
 
398
424
  developmentMetrics.clientArtifactBuilds += 1;
425
+ const buildStartedAt = performance.now();
426
+ reportDevelopmentEvent({
427
+ type: "client-assets-building",
428
+ entryCount: devBundledEntries.size,
429
+ });
399
430
  const bundledClientAssets = await emitBundledClientAssetsWithState(projectRoot, {
400
431
  mode: "development",
401
432
  entryClientModules: devBundledEntries,
@@ -415,6 +446,11 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
415
446
  },
416
447
  ) ?? currentHydrationModuleUrl;
417
448
  devRollupCache = bundledClientAssets.rollupCache;
449
+ reportDevelopmentEvent({
450
+ type: "client-assets-ready",
451
+ durationMs: Math.round(performance.now() - buildStartedAt),
452
+ entryCount: devBundledEntries.size,
453
+ });
418
454
  });
419
455
  },
420
456
  async resolveRoutePolicy(request) {
@@ -453,7 +489,26 @@ export async function createDeploymentRuntime({
453
489
  assetManifest,
454
490
  responseCacheRuntime,
455
491
  routeResolver,
492
+ onDevelopmentEvent,
456
493
  } = {}) {
494
+ function reportDevelopmentEvent(event) {
495
+ if (mode === "development" && typeof onDevelopmentEvent === "function") {
496
+ onDevelopmentEvent(event);
497
+ }
498
+ }
499
+
500
+ if (mode === "development") {
501
+ reportDevelopmentEvent({ type: "initializing" });
502
+ const developmentRoot = path.join(projectRoot, INTERNAL_DIRECTORY, DEV_DIRECTORY);
503
+ await fs.rm(developmentRoot, { recursive: true, force: true });
504
+ invalidateDevelopmentCompilationCache(projectRoot);
505
+ resetDevelopmentAssetCaches(projectRoot);
506
+ await buildSharedVendorRuntime(projectRoot, "development", {
507
+ additionalEntrySpecifiers: [],
508
+ });
509
+ reportDevelopmentEvent({ type: "vendor-runtime-ready" });
510
+ }
511
+
457
512
  const effectiveResponseCacheRuntime = responseCacheRuntime
458
513
  ?? await resolveResponseCacheRuntime(
459
514
  projectRoot,
@@ -461,7 +516,7 @@ export async function createDeploymentRuntime({
461
516
  await loadEvolitConfig(projectRoot),
462
517
  );
463
518
  const runtimeState = {
464
- assetManifest: normalizeClientAssetManifest(assetManifest),
519
+ assetManifest: mode === "development" ? null : normalizeClientAssetManifest(assetManifest),
465
520
  };
466
521
  const assets = createPublicAssetOrigin({
467
522
  projectRoot,
@@ -476,6 +531,7 @@ export async function createDeploymentRuntime({
476
531
  assetManifest: runtimeState.assetManifest,
477
532
  responseCacheRuntime: effectiveResponseCacheRuntime,
478
533
  routeResolver,
534
+ onDevelopmentEvent,
479
535
  });
480
536
 
481
537
  return {
package/src/render.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  isEvolitHttpSignal,
13
13
  runWithRequestContext,
14
14
  } from "./request-context.js";
15
+ import { terminal } from "./terminal.js";
15
16
  import {
16
17
  LITSX_COMPONENT,
17
18
  LITSX_SERVER_COMPONENT,
@@ -89,7 +90,10 @@ function createBoundaryError(error, { mode, route, reportRouteError }) {
89
90
  if (typeof reportRouteError === "function") {
90
91
  reportRouteError(report);
91
92
  } else {
92
- console.error(`[evolit] Route rendering failed (${digest}) at ${route.pathname}`, originalError);
93
+ console.error(
94
+ `${terminal.red("[evolit]")} ${terminal.red("✖")} Route rendering failed ${terminal.dim(`(${digest})`)} at ${terminal.cyan(route.pathname)}`,
95
+ originalError,
96
+ );
93
97
  }
94
98
 
95
99
  const boundaryError = new Error("An unexpected server error occurred.");
@@ -133,6 +137,7 @@ function createRouteModuleOptions(projectRoot, mode, options = {}) {
133
137
  mode,
134
138
  ssr: true,
135
139
  staticAssetPublicUrls: resolvedStaticAssetPublicUrls,
140
+ onDevelopmentEvent: options.onDevelopmentEvent,
136
141
  };
137
142
  }
138
143
 
package/src/server.js CHANGED
@@ -9,6 +9,7 @@ import { APP_DIRECTORY, BUILD_DIRECTORY, INTERNAL_DIRECTORY, MANIFEST_FILENAME }
9
9
  import { normalizeClientAssetManifest } from "./client-assets.js";
10
10
  import { pathExists, readJson } from "./fs-utils.js";
11
11
  import { createDefaultRouteCacheKey, resolveResponseCacheRuntime } from "./response-cache.js";
12
+ import { terminal } from "./terminal.js";
12
13
 
13
14
  function getPort(explicitPort) {
14
15
  const port = explicitPort ?? process.env.PORT ?? "3000";
@@ -139,6 +140,58 @@ async function createRecursiveDirectoryWatcher(rootDirectory, onChange) {
139
140
  }
140
141
 
141
142
  async function createServer(projectRoot, mode, explicitPort, options = {}) {
143
+ const reportDevelopmentEvent = mode === "development"
144
+ ? options.onDevelopmentEvent ?? ((event) => {
145
+ switch (event.type) {
146
+ case "initializing":
147
+ console.log(`${terminal.cyan("[evolit]")} ${terminal.yellow("○")} Preparing development runtime…`);
148
+ break;
149
+ case "vendor-runtime-ready":
150
+ console.log(`${terminal.cyan("[evolit]")} ${terminal.green("✓")} Vendor runtime ready.`);
151
+ break;
152
+ case "client-assets-building":
153
+ console.log(`${terminal.cyan("[evolit]")} ${terminal.magenta("○")} Compiling client assets (${event.entryCount} entries)…`);
154
+ break;
155
+ case "client-assets-ready":
156
+ console.log(`${terminal.cyan("[evolit]")} ${terminal.green("✓")} Client assets compiled in ${terminal.dim(`${event.durationMs}ms`)} (${event.entryCount} entries).`);
157
+ break;
158
+ case "client-assets-cache-hit":
159
+ console.log(`${terminal.cyan("[evolit]")} ${terminal.blue("●")} Client assets served from cache.`);
160
+ break;
161
+ case "invalidated":
162
+ console.log(
163
+ `${terminal.cyan("[evolit]")} ${terminal.yellow("△")} Source change detected${event.changedPathCount == null ? "" : ` (${event.changedPathCount} files)`}; invalidated ${event.affectedClientEntryCount} client entries.`,
164
+ );
165
+ break;
166
+ case "external-import":
167
+ console.warn(
168
+ `${terminal.yellow("[evolit]")} ${terminal.yellow("⚠")} Development import ${terminal.cyan(JSON.stringify(event.resolvedImportPath))} from ${terminal.cyan(JSON.stringify(event.sourcePath))} is outside the project root. It will be emitted under ${terminal.cyan("/_evolit/static/__external__/")}.`,
169
+ );
170
+ break;
171
+ case "request": {
172
+ const statusColor = event.status >= 500
173
+ ? terminal.red
174
+ : event.status >= 400
175
+ ? terminal.yellow
176
+ : event.status >= 300
177
+ ? terminal.blue
178
+ : terminal.green;
179
+ console.log(
180
+ `${terminal.cyan("[evolit]")} ${terminal.dim(event.method)} ${event.pathname} ${statusColor(event.status)} in ${terminal.dim(`${event.durationMs}ms`)}${event.cacheState ? ` ${terminal.blue(`(${event.cacheState})`)}` : ""}`,
181
+ );
182
+ break;
183
+ }
184
+ case "request-error":
185
+ console.error(
186
+ `${terminal.red("[evolit]")} ${terminal.red("✖")} ${event.method} ${event.pathname} failed`,
187
+ event.error,
188
+ );
189
+ break;
190
+ default:
191
+ break;
192
+ }
193
+ })
194
+ : null;
142
195
  const evolitConfig = options.evolitConfig ?? await loadEvolitConfig(projectRoot);
143
196
  const responseCacheRuntime = options.responseCacheStore
144
197
  ? {
@@ -151,6 +204,7 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
151
204
  mode,
152
205
  assetManifest: normalizeClientAssetManifest(options.assetManifest),
153
206
  responseCacheRuntime,
207
+ onDevelopmentEvent: reportDevelopmentEvent,
154
208
  });
155
209
  const port = getPort(explicitPort);
156
210
  const liveReloadServer = mode === "development" ? new WebSocketServer({ noServer: true }) : null;
@@ -226,6 +280,7 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
226
280
  headers: req.headers,
227
281
  ...(method === "GET" || method === "HEAD" ? {} : { body: req, duplex: "half" }),
228
282
  });
283
+ const requestStartedAt = performance.now();
229
284
  const response = await deploymentRuntime.handle(request);
230
285
  const servedResponse = mode === "development"
231
286
  ? injectLiveReloadSnippet(response)
@@ -233,7 +288,24 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
233
288
 
234
289
  res.writeHead(servedResponse.status, servedResponse.headers);
235
290
  await writeResponseBody(res, servedResponse.body);
291
+ if (mode === "development" && !pathname.startsWith("/_evolit/")) {
292
+ const durationMs = Math.round(performance.now() - requestStartedAt);
293
+ reportDevelopmentEvent({
294
+ type: "request",
295
+ method,
296
+ pathname,
297
+ status: servedResponse.status,
298
+ durationMs,
299
+ cacheState: servedResponse.headers?.["x-evolit-cache"] ?? null,
300
+ });
301
+ }
236
302
  } catch (error) {
303
+ reportDevelopmentEvent?.({
304
+ type: "request-error",
305
+ method: req.method ?? "GET",
306
+ pathname: req.url ?? "/",
307
+ error,
308
+ });
237
309
  res.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
238
310
  res.end(error instanceof Error ? error.stack ?? error.message : String(error));
239
311
  }
@@ -0,0 +1,32 @@
1
+ const enabled = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
2
+
3
+ function style(open, value) {
4
+ return enabled ? `\u001B[${open}m${value}\u001B[0m` : String(value);
5
+ }
6
+
7
+ export const terminal = {
8
+ bold(value) {
9
+ return style("1", value);
10
+ },
11
+ dim(value) {
12
+ return style("2", value);
13
+ },
14
+ red(value) {
15
+ return style("31", value);
16
+ },
17
+ green(value) {
18
+ return style("32", value);
19
+ },
20
+ yellow(value) {
21
+ return style("33", value);
22
+ },
23
+ blue(value) {
24
+ return style("34", value);
25
+ },
26
+ magenta(value) {
27
+ return style("35", value);
28
+ },
29
+ cyan(value) {
30
+ return style("36", value);
31
+ },
32
+ };