@@ -19,7 +19,7 @@ import strings from '../../../resources';
19
19
import * as urlBuilder from '../../domain/url-builder' ;
20
20
import * as validator from '../../domain/validators' ;
21
21
import type { Repository } from '../../domain/repository' ;
22
- import { Config } from '../../../types' ;
22
+ import { Component , Config } from '../../../types' ;
23
23
import { IncomingHttpHeaders } from 'http' ;
24
24
import { fromPromise } from 'universalify' ;
25
25
@@ -61,6 +61,22 @@ export default function getComponent(conf: Config, repository: Repository) {
61
61
refreshInterval : conf . refreshInterval
62
62
} ) ;
63
63
64
+ const getEnv = async (
65
+ component : Component
66
+ ) : Promise < Record < string , string > > => {
67
+ const cacheKey = `${ component . name } /${ component . version } /.env` ;
68
+ const cached = cache . get ( 'file-contents' , cacheKey ) ;
69
+
70
+ if ( cached ) return cached ;
71
+
72
+ const env = component . oc . files . env
73
+ ? await repository . getEnv ( component . name , component . version )
74
+ : { } ;
75
+ cache . set ( 'file-contents' , cacheKey , env ) ;
76
+
77
+ return env ;
78
+ } ;
79
+
64
80
const renderer = function (
65
81
options : RendererOptions ,
66
82
cb : ( result : GetComponentResult ) => void
@@ -411,136 +427,152 @@ export default function getComponent(conf: Config, repository: Repository) {
411
427
if ( ! component . oc . files . dataProvider ) {
412
428
returnComponent ( null , { } ) ;
413
429
} else {
414
- const cacheKey = `${ component . name } /${ component . version } /server.js` ;
415
- const cached = cache . get ( 'file-contents' , cacheKey ) ;
416
- const domain = Domain . create ( ) ;
417
- const setEmptyResponse =
418
- emptyResponseHandler . contextDecorator ( returnComponent ) ;
419
- const contextObj = {
420
- acceptLanguage : acceptLanguageParser . parse ( acceptLanguage ! ) ,
421
- baseUrl : conf . baseUrl ,
422
- env : conf . env ,
423
- params,
424
- plugins : conf . plugins ,
425
- renderComponent : fromPromise ( nestedRenderer . renderComponent ) ,
426
- renderComponents : fromPromise ( nestedRenderer . renderComponents ) ,
427
- requestHeaders : options . headers ,
428
- requestIp : options . ip ,
429
- setEmptyResponse,
430
- staticPath : repository
431
- . getStaticFilePath ( component . name , component . version , '' )
432
- . replace ( 'https:' , '' ) ,
433
- setHeader : ( header ?: string , value ?: string ) => {
434
- if ( ! ( typeof header === 'string' && typeof value === 'string' ) ) {
435
- throw strings . errors . registry
436
- . COMPONENT_SET_HEADER_PARAMETERS_NOT_VALID ;
437
- }
438
-
439
- if ( header && value ) {
440
- responseHeaders = responseHeaders || { } ;
441
- responseHeaders [ header . toLowerCase ( ) ] = value ;
442
- }
443
- } ,
444
- templates : repository . getTemplatesInfo ( )
445
- } ;
446
-
447
- const setCallbackTimeout = ( ) => {
448
- const executionTimeout = conf . executionTimeout ;
449
- if ( executionTimeout ) {
450
- setTimeout ( ( ) => {
451
- const message = `timeout (${ executionTimeout * 1000 } ms)` ;
452
- returnComponent ( { message } , undefined ) ;
453
- domain . exit ( ) ;
454
- } , executionTimeout * 1000 ) ;
430
+ fromPromise ( getEnv ) ( component , ( err , env ) => {
431
+ if ( err ) {
432
+ componentCallbackDone = true ;
433
+
434
+ return callback ( {
435
+ status : 502 ,
436
+ response : {
437
+ code : 'ENV_RESOLVING_ERROR' ,
438
+ error : strings . errors . registry . RESOLVING_ERROR
439
+ }
440
+ } ) ;
455
441
}
456
- } ;
457
442
458
- if ( ! ! cached && ! conf . hotReloading ) {
459
- domain . on ( 'error' , returnComponent ) ;
443
+ const cacheKey = `${ component . name } /${ component . version } /server.js` ;
444
+ const cached = cache . get ( 'file-contents' , cacheKey ) ;
445
+ const domain = Domain . create ( ) ;
446
+ const setEmptyResponse =
447
+ emptyResponseHandler . contextDecorator ( returnComponent ) ;
448
+ const contextObj = {
449
+ acceptLanguage : acceptLanguageParser . parse ( acceptLanguage ! ) ,
450
+ baseUrl : conf . baseUrl ,
451
+ env : { ...conf . env , ...env } ,
452
+ params,
453
+ plugins : conf . plugins ,
454
+ renderComponent : fromPromise ( nestedRenderer . renderComponent ) ,
455
+ renderComponents : fromPromise ( nestedRenderer . renderComponents ) ,
456
+ requestHeaders : options . headers ,
457
+ requestIp : options . ip ,
458
+ setEmptyResponse,
459
+ staticPath : repository
460
+ . getStaticFilePath ( component . name , component . version , '' )
461
+ . replace ( 'https:' , '' ) ,
462
+ setHeader : ( header ?: string , value ?: string ) => {
463
+ if (
464
+ ! ( typeof header === 'string' && typeof value === 'string' )
465
+ ) {
466
+ throw strings . errors . registry
467
+ . COMPONENT_SET_HEADER_PARAMETERS_NOT_VALID ;
468
+ }
460
469
461
- try {
462
- domain . run ( ( ) => {
463
- cached ( contextObj , returnComponent ) ;
464
- setCallbackTimeout ( ) ;
465
- } ) ;
466
- } catch ( e ) {
467
- return returnComponent ( e , undefined ) ;
468
- }
469
- } else {
470
- fromPromise ( repository . getDataProvider ) (
471
- component . name ,
472
- component . version ,
473
- ( err , dataProvider ) => {
474
- if ( err ) {
475
- componentCallbackDone = true ;
476
-
477
- return callback ( {
478
- status : 502 ,
479
- response : {
480
- code : 'DATA_RESOLVING_ERROR' ,
481
- error : strings . errors . registry . RESOLVING_ERROR
482
- }
483
- } ) ;
470
+ if ( header && value ) {
471
+ responseHeaders = responseHeaders || { } ;
472
+ responseHeaders [ header . toLowerCase ( ) ] = value ;
484
473
}
474
+ } ,
475
+ templates : repository . getTemplatesInfo ( )
476
+ } ;
485
477
486
- const context = {
487
- require : RequireWrapper ( conf . dependencies ) ,
488
- module : {
489
- exports : { } as Record <
490
- string ,
491
- ( ...args : unknown [ ] ) => unknown
492
- >
493
- } ,
494
- console : conf . local ? console : { log : _ . noop } ,
495
- setTimeout,
496
- Buffer
497
- } ;
498
-
499
- const handleError = ( err : {
500
- code : string ;
501
- missing : string [ ] ;
502
- } ) => {
503
- if ( err . code === 'DEPENDENCY_MISSING_FROM_REGISTRY' ) {
478
+ const setCallbackTimeout = ( ) => {
479
+ const executionTimeout = conf . executionTimeout ;
480
+ if ( executionTimeout ) {
481
+ setTimeout ( ( ) => {
482
+ const message = `timeout (${ executionTimeout * 1000 } ms)` ;
483
+ returnComponent ( { message } , undefined ) ;
484
+ domain . exit ( ) ;
485
+ } , executionTimeout * 1000 ) ;
486
+ }
487
+ } ;
488
+
489
+ if ( ! ! cached && ! conf . hotReloading ) {
490
+ domain . on ( 'error' , returnComponent ) ;
491
+
492
+ try {
493
+ domain . run ( ( ) => {
494
+ cached ( contextObj , returnComponent ) ;
495
+ setCallbackTimeout ( ) ;
496
+ } ) ;
497
+ } catch ( e ) {
498
+ return returnComponent ( e , undefined ) ;
499
+ }
500
+ } else {
501
+ fromPromise ( repository . getDataProvider ) (
502
+ component . name ,
503
+ component . version ,
504
+ ( err , dataProvider ) => {
505
+ if ( err ) {
504
506
componentCallbackDone = true ;
505
507
506
508
return callback ( {
507
- status : 501 ,
509
+ status : 502 ,
508
510
response : {
509
- code : err . code ,
510
- error : strings . errors . registry . DEPENDENCY_NOT_FOUND (
511
- err . missing . join ( ', ' )
512
- ) ,
513
- missingDependencies : err . missing
511
+ code : 'DATA_RESOLVING_ERROR' ,
512
+ error : strings . errors . registry . RESOLVING_ERROR
514
513
}
515
514
} ) ;
516
515
}
517
516
518
- returnComponent ( err , undefined ) ;
519
- } ;
520
-
521
- const options = conf . local
522
- ? {
523
- displayErrors : true ,
524
- filename : dataProvider . filePath
517
+ const context = {
518
+ require : RequireWrapper ( conf . dependencies ) ,
519
+ module : {
520
+ exports : { } as Record <
521
+ string ,
522
+ ( ...args : unknown [ ] ) => unknown
523
+ >
524
+ } ,
525
+ console : conf . local ? console : { log : _ . noop } ,
526
+ setTimeout,
527
+ Buffer
528
+ } ;
529
+
530
+ const handleError = ( err : {
531
+ code : string ;
532
+ missing : string [ ] ;
533
+ } ) => {
534
+ if ( err . code === 'DEPENDENCY_MISSING_FROM_REGISTRY' ) {
535
+ componentCallbackDone = true ;
536
+
537
+ return callback ( {
538
+ status : 501 ,
539
+ response : {
540
+ code : err . code ,
541
+ error : strings . errors . registry . DEPENDENCY_NOT_FOUND (
542
+ err . missing . join ( ', ' )
543
+ ) ,
544
+ missingDependencies : err . missing
545
+ }
546
+ } ) ;
525
547
}
526
- : { } ;
527
548
528
- try {
529
- vm . runInNewContext ( dataProvider . content , context , options ) ;
530
- const processData = context . module . exports [ 'data' ] ;
531
- cache . set ( 'file-contents' , cacheKey , processData ) ;
549
+ returnComponent ( err , undefined ) ;
550
+ } ;
532
551
533
- domain . on ( 'error' , handleError ) ;
534
- domain . run ( ( ) => {
535
- processData ( contextObj , returnComponent ) ;
536
- setCallbackTimeout ( ) ;
537
- } ) ;
538
- } catch ( err ) {
539
- handleError ( err as any ) ;
552
+ const options = conf . local
553
+ ? {
554
+ displayErrors : true ,
555
+ filename : dataProvider . filePath
556
+ }
557
+ : { } ;
558
+
559
+ try {
560
+ vm . runInNewContext ( dataProvider . content , context , options ) ;
561
+ const processData = context . module . exports [ 'data' ] ;
562
+ cache . set ( 'file-contents' , cacheKey , processData ) ;
563
+
564
+ domain . on ( 'error' , handleError ) ;
565
+ domain . run ( ( ) => {
566
+ processData ( contextObj , returnComponent ) ;
567
+ setCallbackTimeout ( ) ;
568
+ } ) ;
569
+ } catch ( err ) {
570
+ handleError ( err as any ) ;
571
+ }
540
572
}
541
- }
542
- ) ;
543
- }
573
+ ) ;
574
+ }
575
+ } ) ;
544
576
}
545
577
}
546
578
) ;
0 commit comments