@@ -27,7 +27,7 @@ export function useRuby(): RuntimeContext {
2727type MessageToWorker =
2828 | {
2929 type : "init" ;
30- payload : { RUBY_WASM_URL : string } ;
30+ payload : { } ;
3131 }
3232 | {
3333 type : "runRuby" ;
@@ -90,13 +90,9 @@ export function RubyProvider({ children }: { children: ReactNode }) {
9090 }
9191 } ;
9292
93- // Use CDN URL for Ruby WASM with stdlib
94- const RUBY_WASM_URL =
95- "https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.7.2/dist/ruby+stdlib.wasm" ;
96-
9793 return postMessage < InitPayloadFromWorker > ( {
9894 type : "init" ,
99- payload : { RUBY_WASM_URL } ,
95+ payload : { } ,
10096 } ) ;
10197 } , [ ] ) ;
10298
@@ -112,32 +108,39 @@ export function RubyProvider({ children }: { children: ReactNode }) {
112108 } ;
113109 } , [ initializeWorker ] ) ;
114110
115- const interrupt = useCallback ( async ( ) => {
111+ const interrupt = useCallback ( ( ) => {
116112 // Terminate the current worker
117113 if ( workerRef . current ) {
118114 workerRef . current . terminate ( ) ;
119115 }
120116
117+ // reject all pending messages
118+ for ( const [ , [ , reject ] ] of messageCallbacks . current ) {
119+ reject ( "Execution interrupted" ) ;
120+ }
121+
121122 // Mark as not ready during reinitialization
122123 setReady ( false ) ;
123124
124- // Reinitialize the worker
125- const { success } = await initializeWorker ( ) ;
126-
127- if ( success ) {
128- // Re-execute all saved commands to restore state
129- for ( const cmd of commandHistory . current ) {
130- try {
131- await postMessage < RunPayloadFromWorker > ( {
132- type : "runRuby" ,
133- payload : { code : cmd } ,
134- } ) ;
135- } catch ( e ) {
136- console . error ( "Error restoring command:" , cmd , e ) ;
125+ void mutex . current . runExclusive ( async ( ) => {
126+ // Reinitialize the worker
127+ const { success } = await initializeWorker ( ) ;
128+
129+ if ( success ) {
130+ // Re-execute all saved commands to restore state
131+ for ( const cmd of commandHistory . current ) {
132+ try {
133+ await postMessage < RunPayloadFromWorker > ( {
134+ type : "runRuby" ,
135+ payload : { code : cmd } ,
136+ } ) ;
137+ } catch ( e ) {
138+ console . error ( "Error restoring command:" , cmd , e ) ;
139+ }
137140 }
141+ setReady ( true ) ;
138142 }
139- setReady ( true ) ;
140- }
143+ } ) ;
141144 } , [ initializeWorker ] ) ;
142145
143146 const runCommand = useCallback (
@@ -152,15 +155,22 @@ export function RubyProvider({ children }: { children: ReactNode }) {
152155 const { output, updatedFiles } = await postMessage < RunPayloadFromWorker > ( {
153156 type : "runRuby" ,
154157 payload : { code } ,
158+ } ) . catch ( ( error ) => {
159+ return {
160+ output : [
161+ { type : "error" , message : `Execution error: ${ error } ` } ,
162+ ] as ReplOutput [ ] ,
163+ updatedFiles : [ ] as [ string , string ] [ ] ,
164+ } ;
155165 } ) ;
156-
166+
157167 // Check if the command succeeded (no errors)
158168 const hasError = output . some ( ( o ) => o . type === "error" ) ;
159169 if ( ! hasError ) {
160170 // Save successful command to history
161171 commandHistory . current . push ( code ) ;
162172 }
163-
173+
164174 for ( const [ name , content ] of updatedFiles ) {
165175 writeFile ( name , content ) ;
166176 }
@@ -201,6 +211,13 @@ export function RubyProvider({ children }: { children: ReactNode }) {
201211 await postMessage < RunPayloadFromWorker > ( {
202212 type : "runFile" ,
203213 payload : { name : filenames [ 0 ] , files } ,
214+ } ) . catch ( ( error ) => {
215+ return {
216+ output : [
217+ { type : "error" , message : `Execution error: ${ error } ` } ,
218+ ] as ReplOutput [ ] ,
219+ updatedFiles : [ ] as [ string , string ] [ ] ,
220+ } ;
204221 } ) ;
205222 for ( const [ newName , content ] of updatedFiles ) {
206223 writeFile ( newName , content ) ;
0 commit comments