@@ -53,11 +53,13 @@ export function makeHandledPromise(Promise) {
53
53
let presenceToHandler ;
54
54
let presenceToPromise ;
55
55
let promiseToHandler ;
56
+ let promiseToPresence ; // only for HandledPromise.unwrap
56
57
function ensureMaps ( ) {
57
58
if ( ! presenceToHandler ) {
58
59
presenceToHandler = new WeakMap ( ) ;
59
60
presenceToPromise = new WeakMap ( ) ;
60
61
promiseToHandler = new WeakMap ( ) ;
62
+ promiseToPresence = new WeakMap ( ) ;
61
63
}
62
64
}
63
65
@@ -109,6 +111,9 @@ export function makeHandledPromise(Promise) {
109
111
// Return undefined.
110
112
} ;
111
113
} ) ;
114
+ // A failed interlock should not be recorded as an unhandled rejection.
115
+ // It will bubble up to the HandledPromise itself.
116
+ interlockP . catch ( _ => { } ) ;
112
117
113
118
const makePostponed = postponedOperation => {
114
119
// Just wait until the handler is resolved/rejected.
@@ -167,6 +172,7 @@ export function makeHandledPromise(Promise) {
167
172
// Create table entries for the presence mapped to the
168
173
// fulfilledHandler.
169
174
presenceToPromise . set ( resolvedPresence , handledP ) ;
175
+ promiseToPresence . set ( handledP , resolvedPresence ) ;
170
176
presenceToHandler . set ( resolvedPresence , presenceHandler ) ;
171
177
172
178
// Remove the mapping, as our presenceHandler should be
@@ -206,10 +212,16 @@ export function makeHandledPromise(Promise) {
206
212
}
207
213
208
214
// See if the target is a presence we already know of.
209
- const presence = await target ;
215
+ let presence ;
216
+ try {
217
+ presence = HandledPromise . unwrap ( target ) ;
218
+ } catch ( e ) {
219
+ presence = await target ;
220
+ }
210
221
const existingPresenceHandler = presenceToHandler . get ( presence ) ;
211
222
if ( existingPresenceHandler ) {
212
223
promiseToHandler . set ( handledP , existingPresenceHandler ) ;
224
+ promiseToPresence . set ( handledP , presence ) ;
213
225
return continueForwarding ( null , handledP ) ;
214
226
}
215
227
@@ -284,6 +296,30 @@ export function makeHandledPromise(Promise) {
284
296
promiseResolve ( ) . then ( _ => new HandledPromise ( executeThen ) ) ,
285
297
) ;
286
298
} ,
299
+ // TODO verify that this is safe to provide universally, i.e.,
300
+ // that by itself it doesn't provide access to mutable state in
301
+ // ways that violate normal ocap module purity rules. The claim
302
+ // that it does not rests on the handled promise itself being
303
+ // necessary to perceive this mutable state. In that sense, we
304
+ // can think of the right to perceive it, and of access to the
305
+ // target, as being in the handled promise. Note that a .then on
306
+ // the handled promise will already provide async access to the
307
+ // target, so the only additional authorities are: 1)
308
+ // synchronous access for handled promises only, and thus 2) the
309
+ // ability to tell, from the client side, whether a promise is
310
+ // handled. Or, at least, the ability to tell given that the
311
+ // promise is already fulfilled.
312
+ unwrap ( value ) {
313
+ ensureMaps ( ) ;
314
+ const pr = presenceToPromise . get ( value ) || value ;
315
+ const presence = promiseToPresence . get ( pr ) ;
316
+ if ( ! presence ) {
317
+ throw TypeError (
318
+ `Value is not a presence nor a HandledPromise resolved to a presence` ,
319
+ ) ;
320
+ }
321
+ return presence ;
322
+ } ,
287
323
} ) ;
288
324
289
325
defineProperties ( HandledPromise , getOwnPropertyDescriptors ( staticMethods ) ) ;
0 commit comments