@@ -32,10 +32,16 @@ import { Editor as MonacoEditor, OnMount, type Monaco } from '@monaco-editor/rea
3232import { Cross2Icon , InfoCircledIcon , Pencil1Icon , TriangleRightIcon } from '@radix-ui/react-icons' ;
3333import { captureException } from '@sentry/react' ;
3434import { useParams } from '@tanstack/react-router' ;
35+ import { Kit } from '../kit' ;
3536import { cn } from '../utils' ;
3637import labApiDefinitionRaw from './lab-api-declaration?raw' ;
3738import { IFrameEvents , LogMessage } from './shared-types' ;
3839
40+ export type PreflightScriptResultData = Omit <
41+ IFrameEvents . Outgoing . EventData . Result ,
42+ 'type' | 'runId'
43+ > ;
44+
3945export const preflightScriptPlugin : GraphiQLPlugin = {
4046 icon : ( ) => (
4147 < svg
@@ -135,14 +141,6 @@ const PreflightScript_TargetFragment = graphql(`
135141
136142export type LogRecord = LogMessage | { type : 'separator' } ;
137143
138- function safeParseJSON ( str : string ) : Record < string , unknown > | null {
139- try {
140- return JSON . parse ( str ) ;
141- } catch {
142- return null ;
143- }
144- }
145-
146144export const enum PreflightWorkerState {
147145 running ,
148146 ready ,
@@ -173,9 +171,24 @@ export function usePreflightScript(args: {
173171
174172 const currentRun = useRef < null | Function > ( null ) ;
175173
176- async function execute ( script = target ?. preflightScript ?. sourceCode ?? '' , isPreview = false ) {
174+ async function execute (
175+ script = target ?. preflightScript ?. sourceCode ?? '' ,
176+ isPreview = false ,
177+ ) : Promise < PreflightScriptResultData > {
178+ const resultEnvironmentVariablesDecoded : PreflightScriptResultData [ 'environmentVariables' ] =
179+ Kit . tryOr (
180+ ( ) => JSON . parse ( latestEnvironmentVariablesRef . current ) ,
181+ ( ) => ( { } ) ,
182+ ) ;
183+ const result : PreflightScriptResultData = {
184+ request : {
185+ headers : [ ] ,
186+ } ,
187+ environmentVariables : resultEnvironmentVariablesDecoded ,
188+ } ;
189+
177190 if ( isPreview === false && ! isPreflightScriptEnabled ) {
178- return safeParseJSON ( latestEnvironmentVariablesRef . current ) ;
191+ return result ;
179192 }
180193
181194 const id = crypto . randomUUID ( ) ;
@@ -201,7 +214,8 @@ export function usePreflightScript(args: {
201214 type : IFrameEvents . Incoming . Event . run ,
202215 id,
203216 script,
204- environmentVariables : ( environmentVariables && safeParseJSON ( environmentVariables ) ) || { } ,
217+ // Preflight Script has read/write relationship with environment variables.
218+ environmentVariables : result . environmentVariables ,
205219 } satisfies IFrameEvents . Incoming . EventData ,
206220 '*' ,
207221 ) ;
@@ -257,16 +271,23 @@ export function usePreflightScript(args: {
257271 }
258272
259273 if ( ev . data . type === IFrameEvents . Outgoing . Event . result ) {
260- const mergedEnvironmentVariables = JSON . stringify (
261- {
262- ...safeParseJSON ( latestEnvironmentVariablesRef . current ) ,
263- ...ev . data . environmentVariables ,
264- } ,
274+ const mergedEnvironmentVariables = {
275+ ...result . environmentVariables ,
276+ ...ev . data . environmentVariables ,
277+ } ;
278+ result . environmentVariables = mergedEnvironmentVariables ;
279+ result . request . headers = ev . data . request . headers ;
280+
281+ // Cause the new state of environment variables to be
282+ // written back to local storage.
283+ const mergedEnvironmentVariablesEncoded = JSON . stringify (
284+ result . environmentVariables ,
265285 null ,
266286 2 ,
267287 ) ;
268- setEnvironmentVariables ( mergedEnvironmentVariables ) ;
269- latestEnvironmentVariablesRef . current = mergedEnvironmentVariables ;
288+ setEnvironmentVariables ( mergedEnvironmentVariablesEncoded ) ;
289+ latestEnvironmentVariablesRef . current = mergedEnvironmentVariablesEncoded ;
290+
270291 setLogs ( logs => [
271292 ...logs ,
272293 {
@@ -301,7 +322,6 @@ export function usePreflightScript(args: {
301322 ] ) ;
302323 setFinished ( ) ;
303324 closedOpenedPrompts ( ) ;
304-
305325 return ;
306326 }
307327
@@ -310,6 +330,27 @@ export function usePreflightScript(args: {
310330 setLogs ( logs => [ ...logs , log ] ) ;
311331 return ;
312332 }
333+
334+ if ( ev . data . type === IFrameEvents . Outgoing . Event . ready ) {
335+ console . debug ( 'preflight sandbox graphiql plugin: noop iframe event:' , ev . data ) ;
336+ return ;
337+ }
338+
339+ if ( ev . data . type === IFrameEvents . Outgoing . Event . start ) {
340+ console . debug ( 'preflight sandbox graphiql plugin: noop iframe event:' , ev . data ) ;
341+ return ;
342+ }
343+
344+ // Window message events can be emitted from unknowable sources.
345+ // For example when our e2e tests runs within Cypress GUI, we see a `MessageEvent` with `.data` of `{ vscodeScheduleAsyncWork: 3 }`.
346+ // Since we cannot know if the event source is Preflight Script, we cannot perform an exhaustive check.
347+ //
348+ // Kit.neverCase(ev.data);
349+ //
350+ console . debug (
351+ 'preflight sandbox graphiql plugin: An unknown window message event received. Ignoring.' ,
352+ ev ,
353+ ) ;
313354 }
314355
315356 window . addEventListener ( 'message' , eventHandler ) ;
@@ -328,7 +369,8 @@ export function usePreflightScript(args: {
328369 window . removeEventListener ( 'message' , eventHandler ) ;
329370
330371 setState ( PreflightWorkerState . ready ) ;
331- return safeParseJSON ( latestEnvironmentVariablesRef . current ) ;
372+
373+ return result ;
332374 } catch ( err ) {
333375 if ( err instanceof Error ) {
334376 setLogs ( prev => [
@@ -346,7 +388,7 @@ export function usePreflightScript(args: {
346388 } ,
347389 ] ) ;
348390 setState ( PreflightWorkerState . ready ) ;
349- return safeParseJSON ( latestEnvironmentVariablesRef . current ) ;
391+ return result ;
350392 }
351393 throw err ;
352394 }
0 commit comments