@@ -78,6 +78,7 @@ import {
78
78
reviveError ,
79
79
ServiceDesignatorSchema ,
80
80
} from "./plugins/core" ;
81
+ import { InspectorProxyController } from "./plugins/core/inspector-proxy" ;
81
82
import {
82
83
Config ,
83
84
Extension ,
@@ -744,12 +745,32 @@ export class Miniflare {
744
745
readonly #webSocketServer: WebSocketServer ;
745
746
readonly #webSocketExtraHeaders: WeakMap < http . IncomingMessage , Headers > ;
746
747
748
+ #maybeInspectorProxyController?: InspectorProxyController ;
749
+ #previousRuntimeInspectorPort?: number ;
750
+
747
751
constructor ( opts : MiniflareOptions ) {
748
752
// Split and validate options
749
753
const [ sharedOpts , workerOpts ] = validateOptions ( opts ) ;
750
754
this . #sharedOpts = sharedOpts ;
751
755
this . #workerOpts = workerOpts ;
752
756
757
+ const workerNamesToProxy = new Set (
758
+ this . #workerOpts
759
+ . filter ( ( { core : { unsafeInspectorProxy } } ) => ! ! unsafeInspectorProxy )
760
+ . map ( ( w ) => w . core . name ?? "" )
761
+ ) ;
762
+
763
+ const enableInspectorProxy = workerNamesToProxy . size > 0 ;
764
+
765
+ if ( enableInspectorProxy ) {
766
+ if ( this . #sharedOpts. core . inspectorPort === undefined ) {
767
+ throw new MiniflareCoreError (
768
+ "ERR_MISSING_INSPECTOR_PROXY_PORT" ,
769
+ "inspector proxy requested but without an inspectorPort specified"
770
+ ) ;
771
+ }
772
+ }
773
+
753
774
// Add to registry after initial options validation, before any servers/
754
775
// child processes are started
755
776
if ( maybeInstanceRegistry !== undefined ) {
@@ -760,6 +781,21 @@ export class Miniflare {
760
781
761
782
this . #log = this . #sharedOpts. core . log ?? new NoOpLog ( ) ;
762
783
784
+ if ( enableInspectorProxy ) {
785
+ if ( this . #sharedOpts. core . inspectorPort === undefined ) {
786
+ throw new MiniflareCoreError (
787
+ "ERR_MISSING_INSPECTOR_PROXY_PORT" ,
788
+ "inspector proxy requested but without an inspectorPort specified"
789
+ ) ;
790
+ }
791
+
792
+ this . #maybeInspectorProxyController = new InspectorProxyController (
793
+ this . #sharedOpts. core . inspectorPort ,
794
+ this . #log,
795
+ workerNamesToProxy
796
+ ) ;
797
+ }
798
+
763
799
this . #liveReloadServer = new WebSocketServer ( { noServer : true } ) ;
764
800
this . #webSocketServer = new WebSocketServer ( {
765
801
noServer : true ,
@@ -1406,14 +1442,21 @@ export class Miniflare {
1406
1442
configuredHost ,
1407
1443
this . #sharedOpts. core . port
1408
1444
) ;
1409
- let inspectorAddress : string | undefined ;
1445
+ let runtimeInspectorAddress : string | undefined ;
1410
1446
if ( this . #sharedOpts. core . inspectorPort !== undefined ) {
1411
- inspectorAddress = this . #getSocketAddress(
1447
+ let runtimeInspectorPort = this . #sharedOpts. core . inspectorPort ;
1448
+ if ( this . #maybeInspectorProxyController !== undefined ) {
1449
+ // if we have an inspector proxy let's use a
1450
+ // random port for the actual runtime inspector
1451
+ runtimeInspectorPort = 0 ;
1452
+ }
1453
+ runtimeInspectorAddress = this . #getSocketAddress(
1412
1454
kInspectorSocket ,
1413
- this . #previousSharedOpts ?. core . inspectorPort ,
1455
+ this . #previousRuntimeInspectorPort ,
1414
1456
"localhost" ,
1415
- this . #sharedOpts . core . inspectorPort
1457
+ runtimeInspectorPort
1416
1458
) ;
1459
+ this . #previousRuntimeInspectorPort = runtimeInspectorPort ;
1417
1460
}
1418
1461
const loopbackAddress = `${
1419
1462
maybeGetLocallyAccessibleHost ( configuredHost ) ??
@@ -1424,7 +1467,7 @@ export class Miniflare {
1424
1467
entryAddress,
1425
1468
loopbackAddress,
1426
1469
requiredSockets,
1427
- inspectorAddress,
1470
+ inspectorAddress : runtimeInspectorAddress ,
1428
1471
verbose : this . #sharedOpts. core . verbose ,
1429
1472
handleRuntimeStdio : this . #sharedOpts. core . handleRuntimeStdio ,
1430
1473
} ;
@@ -1445,6 +1488,19 @@ export class Miniflare {
1445
1488
// all of `requiredSockets` as keys.
1446
1489
this . #socketPorts = maybeSocketPorts ;
1447
1490
1491
+ if ( this . #maybeInspectorProxyController !== undefined ) {
1492
+ // Try to get inspector port for the workers
1493
+ const maybePort = this . #socketPorts. get ( kInspectorSocket ) ;
1494
+ if ( maybePort === undefined ) {
1495
+ throw new MiniflareCoreError (
1496
+ "ERR_RUNTIME_FAILURE" ,
1497
+ "Unable to access the runtime inspector socket."
1498
+ ) ;
1499
+ } else {
1500
+ this . #maybeInspectorProxyController. updateConnection ( maybePort ) ;
1501
+ }
1502
+ }
1503
+
1448
1504
const entrySocket = config . sockets ?. [ 0 ] ;
1449
1505
const secure = entrySocket !== undefined && "https" in entrySocket ;
1450
1506
const previousEntryURL = this . #runtimeEntryURL;
@@ -1527,6 +1583,8 @@ export class Miniflare {
1527
1583
// `dispose()`d synchronously, immediately after constructing a `Miniflare`
1528
1584
// instance. In this case, return a discard URL which we'll ignore.
1529
1585
if ( disposing ) return new URL ( "http://[100::]/" ) ;
1586
+ // if there is an inspector proxy let's wait for it to be ready
1587
+ await this . #maybeInspectorProxyController?. ready ;
1530
1588
// Make sure `dispose()` wasn't called in the time we've been waiting
1531
1589
this . #checkDisposed( ) ;
1532
1590
// `#runtimeEntryURL` is assigned in `#assembleAndUpdateConfig()`, which is
@@ -1551,6 +1609,10 @@ export class Miniflare {
1551
1609
this . #checkDisposed( ) ;
1552
1610
await this . ready ;
1553
1611
1612
+ if ( this . #maybeInspectorProxyController !== undefined ) {
1613
+ return this . #maybeInspectorProxyController. getInspectorURL ( ) ;
1614
+ }
1615
+
1554
1616
// `#socketPorts` is assigned in `#assembleAndUpdateConfig()`, which is
1555
1617
// called by `#init()`, and `ready` doesn't resolve until `#init()` returns
1556
1618
assert ( this . #socketPorts !== undefined ) ;
@@ -1900,6 +1962,9 @@ export class Miniflare {
1900
1962
// `rm -rf ${#tmpPath}`, this won't throw if `#tmpPath` doesn't exist
1901
1963
await fs . promises . rm ( this . #tmpPath, { force : true , recursive : true } ) ;
1902
1964
1965
+ // Close the inspector proxy server if there is one
1966
+ await this . #maybeInspectorProxyController?. dispose ( ) ;
1967
+
1903
1968
// Remove from instance registry as last step in `finally`, to make sure
1904
1969
// all dispose steps complete
1905
1970
maybeInstanceRegistry ?. delete ( this ) ;
0 commit comments