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