tc39 / proposal-mass-proxy-revocation

Proposal for revoking proxies en masse.
MIT License
4 stars 1 forks source link

Shape of the revocation signal? #14

Open ajvincent opened 1 year ago

ajvincent commented 1 year ago

@caridy has challenged whether the signal property of my proposed options dictionary should be a callable function.

I am completely open to any workable mechanism. I suggested a function as the signal in the naive belief that calling the function would trigger the mass revocation.

Ideas most welcome!

ljharb commented 1 year ago

Why would a function be unable to cross realms? ShadowRealms auto-wrap callables and produce a callable.

Jack-Works commented 1 year ago

@ljharb because the wrapped function does not "unwrapped" when transfer back to the original realm.

ljharb commented 1 year ago

The signal wouldn’t be the function itself tho, it’d be invoking the function - if the signal has identity that matters, only a symbol makes sense.

ajvincent commented 1 year ago

My thinking is that we're reduced to one of two options: either the signal is callable, or the signal has to be passed to a callable as an argument to force the revocation.

As an analogy to Caridy's argument, I'd ask: what happens when we pass a regular Proxy revoker from Proxy.revocable() across a realm boundary, and then call the wrapped revoker? I don't see a real difference between that and the current proposal.

I shudder to think what would happen to the "pass as an argument" option across realms when the realm receiving the signal is a Compartment (i.e. has its own top-level globals like Function, Object, Proxy, etc.).

ljharb commented 1 year ago

A Proxy revoker is a function, so calling the wrapped revoker would absolutely just call the original revoker.

ajvincent commented 1 year ago

A Proxy revoker is a function, so calling the wrapped revoker would absolutely just call the original revoker.

That's what I thought - and that's why I don't see a difference. It may be that Caridy is thinking about the return value of our signal callable... which we haven't specified. (I was thinking undefined, again just like the existing revoker specification.)

caridy commented 1 year ago

It is not about the fact that you can call it from another realm... it is about the fact that you can't use it as a signal to create proxies on the other side under the same umbrella (same signal). Basically, the wrapped version of the signal is not good in new Proxy({}, {}, { signal })

ljharb commented 1 year ago

ah, if the signal is an identity, rather than an action, then it ofc would have to be a symbol.

ajvincent commented 1 year ago

It is not about the fact that you can call it from another realm... it is about the fact that you can't use it as a signal to create proxies on the other side under the same umbrella (same signal). Basically, the wrapped version of the signal is not good in new Proxy({}, {}, { signal })

Oops. I completely misunderstood your argument in the SES meeting. Thank you for the clarification. I've updated the start of this issue to reflect this.

:thinking:

ajvincent commented 1 year ago

Let's assume signal must be a Symbol. The simplest solution would be to have a static method of Proxy which takes the signal as its first (and only) argument.

From there, it becomes a naming convention / API debate: one for the creation of the signal, one for exercising the signal to force revocation. I would propose two methods of Proxy. In TypeScript:

interface ProxyConstructor {
  createSignal() : symbol;
  finalizeSignal(signal: symbol): void;
}

declare var Proxy: ProxyConstructor;

The names are flexible. I just wanted to get away from my proposal's Proxy.revocationController() name for autocomplete purposes (too similar to "revocable").

I still wonder if we'd need a carve-out in the compartments implementation so that a symbol from one compartment could be passed into finalizeSignal() in another compartment.