@@ -6,12 +6,8 @@ import * as fs from 'node:fs';
66import * as http from 'node:http' ;
77import * as path from 'node:path' ;
88
9- import {
10- bundle ,
11- BUNDLER_FILE_EXT_REGEX ,
12- inferLoader ,
13- InstrumentBundlerError
14- } from '@opendatacapture/instrument-bundler' ;
9+ import { formatError } from '@douglasneuroinformatics/libjs' ;
10+ import { bundle , BUNDLER_FILE_EXT_REGEX , inferLoader } from '@opendatacapture/instrument-bundler' ;
1511import type { BundlerInput } from '@opendatacapture/instrument-bundler' ;
1612import { encodeUnicodeToBase64 } from '@opendatacapture/runtime-internal' ;
1713import { generateMetadata , resolveRuntimeAsset } from '@opendatacapture/runtime-meta' ;
@@ -24,13 +20,28 @@ import type { RootProps } from './root';
2420
2521declare const __TAILWIND_STYLES__ : string ;
2622
23+ function timestamp ( ) : string {
24+ return chalk . dim ( new Date ( ) . toLocaleTimeString ( 'en' , { hour12 : false } ) ) ;
25+ }
26+
27+ function log ( message : string ) : void {
28+ console . log ( `${ timestamp ( ) } ${ message } ` ) ;
29+ }
30+
31+ function logError ( message : string ) : void {
32+ console . error ( `${ timestamp ( ) } ${ message } ` ) ;
33+ }
34+
2735class InstrumentLoader {
2836 private encodedBundle : null | string ;
2937
30- constructor ( private readonly target : string ) {
38+ constructor (
39+ private readonly target : string ,
40+ private readonly verbose : boolean
41+ ) {
3142 this . encodedBundle = null ;
3243 fs . watch ( target , { recursive : false } , ( ) => {
33- console . log ( chalk . yellow ( '↺' ) + chalk . dim ( ' File changed, rebuilding instrument ...' ) ) ;
44+ log ( chalk . yellow ( '↺' ) + chalk . dim ( ' File changed, rebuilding...' ) ) ;
3445 void this . updateEncodedBundle ( ) ;
3546 } ) ;
3647 }
@@ -58,35 +69,36 @@ class InstrumentLoader {
5869 name : path . basename ( filepath )
5970 } ) ;
6071 }
72+ const start = Date . now ( ) ;
6173 try {
6274 this . encodedBundle = encodeUnicodeToBase64 ( await bundle ( { inputs } ) ) ;
63- console . log ( chalk . green ( '✓' ) + chalk . dim ( ' Bundle ready' ) ) ;
75+ const elapsed = Date . now ( ) - start ;
76+ const timing = this . verbose ? chalk . dim ( ` (${ elapsed } ms)` ) : '' ;
77+ log ( chalk . green ( '✓' ) + chalk . dim ( ' Bundle ready' ) + timing ) ;
6478 } catch ( err ) {
65- if ( ! ( err instanceof InstrumentBundlerError ) ) {
66- console . error ( err ) ;
67- }
68- console . error ( chalk . red ( '✘ Failed to compile instrument' ) ) ;
79+ const formattedError = err instanceof Error ? formatError ( err ) : err ;
80+ logError ( chalk . dim ( String ( formattedError ) ) + '\n' ) ;
81+ logError ( chalk . red ( '✘' ) + chalk . bold . red ( ' Error: Failed to compile instrument' ) ) ;
6982 }
7083 }
7184}
7285
7386class RequestHandler {
7487 private instrumentLoader : InstrumentLoader ;
7588 private runtimeMetadata : RuntimeMetadataMap ;
89+ private verbose : boolean ;
7690
77- constructor ( params : { instrumentLoader : InstrumentLoader ; runtimeMetadata : RuntimeMetadataMap } ) {
91+ constructor ( params : { instrumentLoader : InstrumentLoader ; runtimeMetadata : RuntimeMetadataMap ; verbose : boolean } ) {
7892 this . instrumentLoader = params . instrumentLoader ;
7993 this . runtimeMetadata = params . runtimeMetadata ;
94+ this . verbose = params . verbose ;
8095 }
8196
8297 async handle ( req : http . IncomingMessage , res : http . ServerResponse ) : Promise < void > {
8398 if ( req . method !== 'GET' ) {
8499 res . writeHead ( 405 , { 'Content-Type' : 'text/plain' } ) ;
85100 res . end ( 'Method Not Allowed' ) ;
86- return ;
87- }
88-
89- if ( req . url === '/' ) {
101+ } else if ( req . url === '/' ) {
90102 const encodedBundle = await this . instrumentLoader . getEncodedBundle ( ) ;
91103 if ( encodedBundle ) {
92104 res . writeHead ( 200 , { 'Content-Type' : 'text/html' } ) ;
@@ -145,11 +157,12 @@ export class Server {
145157 this . server = http . createServer ( ( ...args ) => void this . handler . handle ( ...args ) ) ;
146158 }
147159
148- static async create ( { port, target } : { port : number ; target : string } ) {
160+ static async create ( { port, target, verbose } : { port : number ; target : string ; verbose : boolean } ) {
149161 return new this ( {
150162 handler : new RequestHandler ( {
151- instrumentLoader : new InstrumentLoader ( target ) ,
152- runtimeMetadata : await generateMetadata ( { rootDir : import . meta. dirname } )
163+ instrumentLoader : new InstrumentLoader ( target , verbose ) ,
164+ runtimeMetadata : await generateMetadata ( { rootDir : import . meta. dirname } ) ,
165+ verbose
153166 } ) ,
154167 port
155168 } ) ;
@@ -158,7 +171,14 @@ export class Server {
158171 async start ( ) : Promise < void > {
159172 return new Promise ( ( resolve ) => {
160173 this . server . listen ( this . port , ( ) => {
161- console . log ( chalk . green ( '✓' ) + ' Listening on ' + chalk . cyan . underline ( `http://localhost:${ this . port } ` ) ) ;
174+ log (
175+ chalk . green ( '✓' ) +
176+ chalk . bold ( ' Ready' ) +
177+ ' ' +
178+ chalk . dim ( '➜' ) +
179+ ' ' +
180+ chalk . cyan . underline ( `http://localhost:${ this . port } ` )
181+ ) ;
162182 resolve ( ) ;
163183 } ) ;
164184 } ) ;
0 commit comments