@@ -67,20 +67,80 @@ vi.mock("agents/mcp", () => ({
6767 } ,
6868} ) ) ;
6969
70- class FakeStorage {
70+ class FakeStorage implements DurableObjectStorage {
7171 private readonly values = new Map < string , unknown > ( ) ;
72+ readonly sql = { } as DurableObjectStorage [ "sql" ] ;
73+ readonly kv = { } as DurableObjectStorage [ "kv" ] ;
7274 alarmAt : number | null = null ;
7375
74- async get < T > ( key : string ) : Promise < T | undefined > {
75- return this . values . get ( key ) as T | undefined ;
76+ async get < T > ( key : string ) : Promise < T | undefined > ;
77+ async get < T > ( keys : string [ ] ) : Promise < Map < string , T > > ;
78+ async get < T > ( keyOrKeys : string | string [ ] ) : Promise < T | undefined | Map < string , T > > {
79+ if ( Array . isArray ( keyOrKeys ) ) {
80+ return new Map ( keyOrKeys . map ( ( key ) => [ key , this . values . get ( key ) as T ] ) ) ;
81+ }
82+ return this . values . get ( keyOrKeys ) as T | undefined ;
83+ }
84+
85+ async put < T > ( key : string , value : T ) : Promise < void > ;
86+ async put < T > ( entries : Record < string , T > | Map < string , T > ) : Promise < void > ;
87+ async put < T > (
88+ keyOrEntries : string | Record < string , T > | Map < string , T > ,
89+ value ?: T ,
90+ ) : Promise < void > {
91+ if ( typeof keyOrEntries === "string" ) {
92+ this . values . set ( keyOrEntries , value ) ;
93+ return ;
94+ }
95+ const entries =
96+ keyOrEntries instanceof Map ? keyOrEntries . entries ( ) : Object . entries ( keyOrEntries ) ;
97+ for ( const [ key , entry ] of entries ) this . values . set ( key , entry ) ;
98+ }
99+
100+ async delete ( key : string ) : Promise < boolean > ;
101+ async delete ( keys : string [ ] ) : Promise < number > ;
102+ async delete ( keyOrKeys : string | string [ ] ) : Promise < boolean | number > {
103+ if ( ! Array . isArray ( keyOrKeys ) ) return this . values . delete ( keyOrKeys ) ;
104+ let deleted = 0 ;
105+ for ( const key of keyOrKeys ) {
106+ if ( this . values . delete ( key ) ) deleted += 1 ;
107+ }
108+ return deleted ;
109+ }
110+
111+ async list < T = unknown > ( ) : Promise < Map < string , T > > {
112+ return new Map ( [ ...this . values . entries ( ) ] . map ( ( [ key , value ] ) => [ key , value as T ] ) ) ;
113+ }
114+
115+ async deleteAll ( ) : Promise < void > {
116+ this . values . clear ( ) ;
117+ this . alarmAt = null ;
118+ }
119+
120+ transaction < T > ( _closure : ( txn : DurableObjectTransaction ) => Promise < T > ) : Promise < T > {
121+ return Promise . resolve ( undefined as T ) ;
122+ }
123+
124+ transactionSync < T > ( _closure : ( ) => T ) : T {
125+ return undefined as T ;
126+ }
127+
128+ async sync ( ) : Promise < void > { }
129+
130+ async getAlarm ( ) : Promise < number | null > {
131+ return this . alarmAt ;
132+ }
133+
134+ async getCurrentBookmark ( ) : Promise < string > {
135+ return "test-bookmark" ;
76136 }
77137
78- async put < T > ( key : string , value : T ) : Promise < void > {
79- this . values . set ( key , value ) ;
138+ async getBookmarkForTime ( _timestamp : number | Date ) : Promise < string > {
139+ return "test-bookmark" ;
80140 }
81141
82- async delete ( key : string ) : Promise < boolean > {
83- return this . values . delete ( key ) ;
142+ onNextSessionRestoreBookmark ( _bookmark : string ) : Promise < string > {
143+ return Promise . resolve ( "test-bookmark" ) ;
84144 }
85145
86146 async setAlarm ( scheduledTime : number | Date ) : Promise < void > {
@@ -92,18 +152,21 @@ class FakeStorage {
92152 }
93153}
94154
95- class FakeDurableObjectState {
155+ class FakeDurableObjectState implements DurableObjectState {
96156 readonly storage = new FakeStorage ( ) ;
97157 readonly id : DurableObjectId ;
158+ readonly props : unknown = undefined ;
159+ readonly facets = { } as DurableObjectState [ "facets" ] ;
98160 readonly ctx = this ;
99161 private waitUntilPromises : Promise < unknown > [ ] = [ ] ;
100162
101163 constructor ( name : string ) {
102- this . id = {
164+ const id : Pick < DurableObjectId , "equals" | "name" | "toString" > = {
103165 equals : ( other : DurableObjectId ) => other . toString ( ) === name ,
104166 name,
105167 toString : ( ) => name ,
106- } as unknown as DurableObjectId ;
168+ } ;
169+ this . id = id as DurableObjectId ;
107170 }
108171
109172 waitUntil ( promise : Promise < unknown > ) : void {
@@ -120,6 +183,34 @@ class FakeDurableObjectState {
120183 blockConcurrencyWhile < T > ( callback : ( ) => Promise < T > ) : Promise < T > {
121184 return callback ( ) ;
122185 }
186+
187+ acceptWebSocket ( _ws : WebSocket , _tags ?: string [ ] ) : void { }
188+
189+ getWebSockets ( _tag ?: string ) : WebSocket [ ] {
190+ return [ ] ;
191+ }
192+
193+ getTags ( _ws : WebSocket ) : string [ ] {
194+ return [ ] ;
195+ }
196+
197+ setWebSocketAutoResponse ( _pair ?: WebSocketRequestResponsePair ) : void { }
198+
199+ getWebSocketAutoResponse ( ) : WebSocketRequestResponsePair | null {
200+ return null ;
201+ }
202+
203+ getWebSocketAutoResponseTimestamp ( _ws : WebSocket ) : Date | null {
204+ return null ;
205+ }
206+
207+ setHibernatableWebSocketEventTimeout ( _timeoutMs ?: number ) : void { }
208+
209+ getHibernatableWebSocketEventTimeout ( ) : number | null {
210+ return null ;
211+ }
212+
213+ abort ( _reason ?: string ) : void { }
123214}
124215
125216class InMemoryExecutionOwnerDirectoryNamespace implements McpExecutionOwnerDirectoryNamespace < string > {
@@ -134,7 +225,7 @@ class InMemoryExecutionOwnerDirectoryNamespace implements McpExecutionOwnerDirec
134225 if ( ! directory ) {
135226 directory = new McpExecutionOwnerDirectoryDO ( {
136227 storage : new FakeStorage ( ) ,
137- } as unknown as DurableObjectState ) ;
228+ } ) ;
138229 this . directories . set ( id , directory ) ;
139230 }
140231 return directory ;
@@ -200,13 +291,6 @@ type PendingApprovalLeaseSnapshot = {
200291 readonly timeout : ReturnType < typeof setTimeout > | null ;
201292} ;
202293
203- type PrivateRuntimeState = {
204- engine : ExecutionEngine < Cause . YieldableError > | null ;
205- dbHandle : TestDbHandle | null ;
206- initialized : boolean ;
207- pendingApprovalLeases : Map < string , PendingApprovalLeaseSnapshot > ;
208- } ;
209-
210294class HarnessSession extends McpAgentSessionDOBase < Cloudflare . Env , TestDbHandle > {
211295 private readonly meta : SessionMeta ;
212296 private readonly fakeState : FakeDurableObjectState ;
@@ -227,7 +311,7 @@ class HarnessSession extends McpAgentSessionDOBase<Cloudflare.Env, TestDbHandle>
227311 readonly forwardModelResumeToOwner ?: HarnessSession [ "modelResumeForward" ] ;
228312 } ) {
229313 const state = new FakeDurableObjectState ( input . sessionId ) ;
230- super ( state as unknown as DurableObjectState , { } as Cloudflare . Env ) ;
314+ super ( state , { } as Cloudflare . Env ) ;
231315 this . fakeState = state ;
232316 this . meta = input . meta ?? sessionMeta ( ) ;
233317 this . directory = mcpExecutionOwnerDirectoryFromNamespace ( input . directoryNamespace ) ;
@@ -269,10 +353,9 @@ class HarnessSession extends McpAgentSessionDOBase<Cloudflare.Env, TestDbHandle>
269353 }
270354
271355 protected override buildMcpServer ( ) : Effect . Effect < BuiltMcpServer > {
272- const runtime = this . runtimeState ( ) ;
273356 return Effect . succeed ( {
274357 mcpServer : new McpServer ( { name : "test" , version : "1.0.0" } ) ,
275- engine : runtime . engine ! ,
358+ engine : this [ " engine" ] ! ,
276359 } ) ;
277360 }
278361
@@ -298,32 +381,25 @@ class HarnessSession extends McpAgentSessionDOBase<Cloudflare.Env, TestDbHandle>
298381 executionId : string ,
299382 response : ResumeResponse ,
300383 ) : Promise < McpSessionModelResumeResult | null > {
301- const local = await Effect . runPromise (
302- this . runtimeState ( ) . engine ! . resume ( executionId , response ) ,
303- ) ;
384+ const local = await Effect . runPromise ( this [ "engine" ] ! . resume ( executionId , response ) ) ;
304385 if ( local ) return { status : "result" , result : formatMcpExecutionOutcome ( local ) } ;
305386 return Effect . runPromise ( this . modelResumeFallback ( executionId , response ) ) ;
306387 }
307388
308389 pendingLease ( executionId : string ) : PendingApprovalLeaseSnapshot | undefined {
309- return this . runtimeState ( ) . pendingApprovalLeases . get ( executionId ) ;
390+ return this [ " pendingApprovalLeases" ] . get ( executionId ) ;
310391 }
311392
312393 pendingLeaseCount ( ) : number {
313- return this . runtimeState ( ) . pendingApprovalLeases . size ;
394+ return this [ " pendingApprovalLeases" ] . size ;
314395 }
315396
316397 private installRuntime ( engine : ExecutionEngine < Cause . YieldableError > ) : void {
317- const runtime = this . runtimeState ( ) ;
318- runtime . engine = engine ;
319- runtime . dbHandle = { end : ( ) => undefined } ;
320- runtime . initialized = true ;
398+ this [ "engine" ] = engine ;
399+ this [ "dbHandle" ] = { end : ( ) => undefined } ;
400+ this [ "initialized" ] = true ;
321401 this . server = new McpServer ( { name : "test" , version : "1.0.0" } ) ;
322402 }
323-
324- private runtimeState ( ) : PrivateRuntimeState {
325- return this as unknown as PrivateRuntimeState ;
326- }
327403}
328404
329405const makeDirectory = ( ) => {
0 commit comments