44 IMCMessageTypeEnum ,
55 ReceiverHandler ,
66} from "@pulse-editor/shared-utils" ;
7+ import { useEffect , useRef , useState } from "react" ;
78import useIMC from "../../lib/use-imc" ;
8- import { useEffect , useState } from "react" ;
99
1010/**
1111 * Register an extension command to listen to IMC messages from the core,
@@ -17,33 +17,38 @@ import { useEffect, useState } from "react";
1717 */
1818export default function useCommand (
1919 commandInfo : CommandInfo ,
20- callbackHandler ?: ( args : any ) => Promise < string | void >
20+ callbackHandler ?: ( args : any ) => Promise < string | void > ,
21+ isExtReady : boolean = true
2122) {
2223 const { isReady, imc } = useIMC ( getReceiverHandlerMap ( ) ) ;
2324
2425 const [ handler , setHandler ] = useState <
2526 ( ( args : any ) => Promise < any > ) | undefined
2627 > ( undefined ) ;
2728
29+ // Queue to hold commands until extension is ready
30+ const commandQueue = useRef < { args : any ; resolve : ( v : any ) => void } [ ] > ( [ ] ) ;
31+
32+ async function executeCommand ( args : any ) {
33+ if ( ! handler ) return ;
34+
35+ const res = await handler ( args ) ;
36+ return res ;
37+ }
38+
2839 function getReceiverHandlerMap ( ) {
2940 const receiverHandlerMap = new Map < IMCMessageTypeEnum , ReceiverHandler > ( [
3041 [
3142 IMCMessageTypeEnum . EditorRunExtCommand ,
32- async ( senderWindow : Window , message : IMCMessage ) => {
43+ async ( _senderWindow : Window , message : IMCMessage ) => {
3344 if ( ! commandInfo ) {
3445 throw new Error ( "Extension command is not available" ) ;
3546 }
3647
37- const {
38- name,
39- args,
40- } : {
41- name : string ;
42- args : any ;
43- } = message . payload ;
48+ const { name, args } : { name : string ; args : any } = message . payload ;
4449
4550 if ( name === commandInfo . name ) {
46- // Check if the parameters match the command's parameters
51+ // Validate parameters
4752 const commandParameters = commandInfo . parameters ;
4853 if (
4954 Object . keys ( args ) . length !== Object . keys ( commandParameters ) . length
@@ -54,6 +59,7 @@ export default function useCommand(
5459 } , got ${ Object . keys ( args ) . length } `
5560 ) ;
5661 }
62+
5763 for ( const [ key , value ] of Object . entries ( args ) ) {
5864 if ( commandInfo . parameters [ key ] === undefined ) {
5965 throw new Error ( `Invalid parameter: ${ key } ` ) ;
@@ -67,23 +73,37 @@ export default function useCommand(
6773 }
6874 }
6975
70- // Execute the command handler with the parameters
71- if ( handler ) {
72- const res = await handler ( args ) ;
73- if ( res ) {
74- return res ;
75- }
76+ // If extension is ready, execute immediately
77+ if ( isExtReady ) {
78+ return await executeCommand ( args ) ;
7679 }
80+
81+ // Otherwise, queue the command and return when executed
82+ return new Promise ( ( resolve ) => {
83+ commandQueue . current . push ( { args, resolve } ) ;
84+ } ) ;
7785 }
7886 } ,
7987 ] ,
8088 ] ) ;
8189 return receiverHandlerMap ;
8290 }
8391
92+ // Flush queued commands when isExtReady becomes true
93+ useEffect ( ( ) => {
94+ if ( isExtReady && commandQueue . current . length > 0 ) {
95+ const pending = [ ...commandQueue . current ] ;
96+ commandQueue . current = [ ] ;
97+ pending . forEach ( async ( { args, resolve } ) => {
98+ const res = await executeCommand ( args ) ;
99+ resolve ( res ) ;
100+ } ) ;
101+ }
102+ } , [ isExtReady ] ) ;
103+
84104 useEffect ( ( ) => {
85105 imc ?. updateReceiverHandlerMap ( getReceiverHandlerMap ( ) ) ;
86- } , [ handler , imc ] ) ;
106+ } , [ handler , imc , isExtReady ] ) ;
87107
88108 useEffect ( ( ) => {
89109 setHandler ( ( ) => callbackHandler ) ;
0 commit comments