@@ -217,6 +217,7 @@ type SandboxConfiguration = {
217217 keepAlive ?: boolean ;
218218 containerTimeouts ?: NonNullable < SandboxOptions [ 'containerTimeouts' ] > ;
219219 transport ?: SandboxTransport ;
220+ labels ?: NonNullable < SandboxOptions [ 'labels' ] > ;
220221} ;
221222
222223type CachedSandboxConfiguration = {
@@ -226,6 +227,7 @@ type CachedSandboxConfiguration = {
226227 keepAlive ?: boolean ;
227228 containerTimeouts ?: NonNullable < SandboxOptions [ 'containerTimeouts' ] > ;
228229 transport ?: SandboxTransport ;
230+ labels ?: NonNullable < SandboxOptions [ 'labels' ] > ;
229231} ;
230232
231233type EgressContainerState = DurableObjectState < { } > & {
@@ -347,6 +349,7 @@ type ConfigurableSandboxStub = {
347349 timeouts : NonNullable < SandboxOptions [ 'containerTimeouts' ] >
348350 ) => Promise < void > ;
349351 setTransport ?: ( transport : SandboxTransport ) => Promise < void > ;
352+ setLabels ?: ( labels : Record < string , string > ) => Promise < void > ;
350353} ;
351354
352355type SandboxProxyStub = ConfigurableSandboxStub & {
@@ -504,6 +507,28 @@ function sameContainerTimeouts(
504507 ) ;
505508}
506509
510+ function sameLabels (
511+ left ?: Record < string , string > ,
512+ right ?: Record < string , string >
513+ ) : boolean {
514+ if ( left === right ) return true ;
515+ if ( ! left || ! right ) return false ;
516+
517+ const leftEntries = Object . entries ( left ) ;
518+ const rightEntries = Object . entries ( right ) ;
519+ if ( leftEntries . length !== rightEntries . length ) return false ;
520+
521+ for ( const [ key , value ] of leftEntries ) {
522+ if ( right [ key ] !== value ) return false ;
523+ }
524+
525+ return true ;
526+ }
527+
528+ function cloneLabels ( labels : Record < string , string > ) : Record < string , string > {
529+ return { ...labels } ;
530+ }
531+
507532function buildSandboxConfiguration (
508533 effectiveId : string ,
509534 options : SandboxOptions | undefined ,
@@ -549,6 +574,13 @@ function buildSandboxConfiguration(
549574 configuration . transport = options . transport ;
550575 }
551576
577+ if (
578+ options ?. labels !== undefined &&
579+ ! sameLabels ( cached ?. labels , options . labels )
580+ ) {
581+ configuration . labels = cloneLabels ( options . labels ) ;
582+ }
583+
552584 return configuration ;
553585}
554586
@@ -558,7 +590,8 @@ function hasSandboxConfiguration(configuration: SandboxConfiguration): boolean {
558590 configuration . sleepAfter !== undefined ||
559591 configuration . keepAlive !== undefined ||
560592 configuration . containerTimeouts !== undefined ||
561- configuration . transport !== undefined
593+ configuration . transport !== undefined ||
594+ configuration . labels !== undefined
562595 ) ;
563596}
564597
@@ -583,6 +616,9 @@ function mergeSandboxConfiguration(
583616 } ) ,
584617 ...( configuration . transport !== undefined && {
585618 transport : configuration . transport
619+ } ) ,
620+ ...( configuration . labels !== undefined && {
621+ labels : cloneLabels ( configuration . labels )
586622 } )
587623 } ;
588624}
@@ -631,6 +667,12 @@ function applySandboxConfiguration(
631667 ) ;
632668 }
633669
670+ if ( configuration . labels !== undefined ) {
671+ operations . push (
672+ stub . setLabels ?.( configuration . labels ) ?? Promise . resolve ( )
673+ ) ;
674+ }
675+
634676 return Promise . all ( operations ) . then ( ( ) => undefined ) ;
635677}
636678
@@ -1368,6 +1410,12 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
13681410 this . hasStoredTransport = true ;
13691411 }
13701412
1413+ const storedLabels =
1414+ await this . ctx . storage . get < Record < string , string > > ( 'labels' ) ;
1415+ if ( storedLabels !== undefined && storedLabels !== null ) {
1416+ this . labels = cloneLabels ( storedLabels ) ;
1417+ }
1418+
13711419 if ( this . interceptHttps ) {
13721420 this . envVars = { ...this . envVars , SANDBOX_INTERCEPT_HTTPS : '1' } ;
13731421 }
@@ -1418,6 +1466,10 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
14181466 if ( configuration . transport !== undefined ) {
14191467 await this . setTransport ( configuration . transport ) ;
14201468 }
1469+
1470+ if ( configuration . labels !== undefined ) {
1471+ await this . setLabels ( configuration . labels ) ;
1472+ }
14211473 }
14221474
14231475 // RPC method to set the sleep timeout. Idempotent: re-applying the same
@@ -1572,6 +1624,21 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
15721624 this . logger . debug ( 'Transport updated' , { transport } ) ;
15731625 }
15741626
1627+ async setLabels ( labels : Record < string , string > ) : Promise < void > {
1628+ const nextLabels = cloneLabels ( labels ) ;
1629+
1630+ if ( sameLabels ( this . labels , nextLabels ) ) return ;
1631+
1632+ await this . ctx . storage . put ( 'labels' , nextLabels ) ;
1633+ this . labels = nextLabels ;
1634+
1635+ if ( this . ctx . container ?. running === true ) {
1636+ this . logger . warn (
1637+ 'Container labels updated while container is running; new labels apply on the next container start'
1638+ ) ;
1639+ }
1640+ }
1641+
15751642 private validateTimeout (
15761643 value : number ,
15771644 name : string ,
0 commit comments