@@ -25,6 +25,7 @@ export { Endpoint };
2525export const proxyMarker = Symbol ( "Comlink.proxy" ) ;
2626export const createEndpoint = Symbol ( "Comlink.endpoint" ) ;
2727export const releaseProxy = Symbol ( "Comlink.releaseProxy" ) ;
28+
2829const throwMarker = Symbol ( "Comlink.thrown" ) ;
2930
3031/**
@@ -176,51 +177,108 @@ export type Local<T> =
176177 }
177178 : unknown ) ;
178179
179- export interface TransferHandler {
180- canHandle ( obj : any ) : boolean ;
181- serialize ( obj : any ) : [ any , Transferable [ ] ] ;
182- deserialize ( obj : any ) : any ;
180+ const isObject = ( val : unknown ) : val is object =>
181+ ( typeof val === "object" && val !== null ) || typeof val === "function" ;
182+
183+ /**
184+ * Customizes the serialization of certain values as determined by `canHandle()`.
185+ *
186+ * @template T The input type being handled by this transfer handler.
187+ * @template S The serialized type sent over the wire.
188+ */
189+ export interface TransferHandler < T , S > {
190+ /**
191+ * Gets called for every value to determine whether this transfer handler
192+ * should serialize the value, which includes checking that it is of the right
193+ * type (but can perform checks beyond that as well).
194+ */
195+ canHandle ( value : unknown ) : value is T ;
196+
197+ /**
198+ * Gets called with the value if `canHandle()` returned `true` to produce a
199+ * value that can be sent in a message, consisting of structured-cloneable
200+ * values and/or transferrable objects.
201+ */
202+ serialize ( value : T ) : [ S , Transferable [ ] ] ;
203+
204+ /**
205+ * Gets called to deserialize an incoming value that was serialized in the
206+ * other thread with this transfer handler (known through the name it was
207+ * registered under).
208+ */
209+ deserialize ( value : S ) : T ;
183210}
184211
185- export const transferHandlers = new Map < string , TransferHandler > ( [
186- [
187- "proxy" ,
188- {
189- canHandle : obj => obj && obj [ proxyMarker ] ,
190- serialize ( obj ) {
191- const { port1, port2 } = new MessageChannel ( ) ;
192- expose ( obj , port1 ) ;
193- return [ port2 , [ port2 ] ] ;
194- } ,
195- deserialize : ( port : MessagePort ) => {
196- port . start ( ) ;
197- return wrap ( port ) ;
198- }
199- }
200- ] ,
201- [
202- "throw" ,
203- {
204- canHandle : obj => typeof obj === "object" && throwMarker in obj ,
205- serialize ( { value } ) {
206- const isError = value instanceof Error ;
207- let serialized = { isError, value } ;
208- if ( isError ) {
209- serialized . value = {
210- message : value . message ,
211- stack : value . stack
212- } ;
213- }
214- return [ serialized , [ ] ] ;
215- } ,
216- deserialize ( serialized ) {
217- if ( serialized . isError ) {
218- throw Object . assign ( new Error ( ) , serialized . value ) ;
212+ /**
213+ * Internal transfer handle to handle objects marked to proxy.
214+ */
215+ const proxyTransferHandler : TransferHandler < object , MessagePort > = {
216+ canHandle : ( val ) : val is ProxyMarked =>
217+ isObject ( val ) && ( val as ProxyMarked ) [ proxyMarker ] ,
218+ serialize ( obj ) {
219+ const { port1, port2 } = new MessageChannel ( ) ;
220+ expose ( obj , port1 ) ;
221+ return [ port2 , [ port2 ] ] ;
222+ } ,
223+ deserialize ( port ) {
224+ port . start ( ) ;
225+ return wrap ( port ) ;
226+ }
227+ } ;
228+
229+ interface ThrownValue {
230+ [ throwMarker ] : unknown ; // just needs to be present
231+ value : unknown ;
232+ }
233+ type SerializedThrownValue =
234+ | { isError : true ; value : Error }
235+ | { isError : false ; value : unknown } ;
236+
237+ /**
238+ * Internal transfer handler to handle thrown exceptions.
239+ */
240+ const throwTransferHandler : TransferHandler <
241+ ThrownValue ,
242+ SerializedThrownValue
243+ > = {
244+ canHandle : ( value ) : value is ThrownValue =>
245+ isObject ( value ) && throwMarker in value ,
246+ serialize ( { value } ) {
247+ let serialized : SerializedThrownValue ;
248+ if ( value instanceof Error ) {
249+ serialized = {
250+ isError : true ,
251+ value : {
252+ message : value . message ,
253+ name : value . name ,
254+ stack : value . stack
219255 }
220- throw serialized . value ;
221- }
256+ } ;
257+ } else {
258+ serialized = { isError : false , value } ;
259+ }
260+ return [ serialized , [ ] ] ;
261+ } ,
262+ deserialize ( serialized ) {
263+ if ( serialized . isError ) {
264+ throw Object . assign (
265+ new Error ( serialized . value . message ) ,
266+ serialized . value
267+ ) ;
222268 }
223- ]
269+ throw serialized . value ;
270+ }
271+ } ;
272+
273+ /**
274+ * Allows customizing the serialization of certain values.
275+ */
276+ export const transferHandlers = new Map <
277+ string ,
278+ TransferHandler < unknown , unknown >
279+ > ( [
280+ [ "proxy" , proxyTransferHandler ] ,
281+ [ "throw" , throwTransferHandler ]
224282] ) ;
225283
226284export function expose ( obj : any , ep : Endpoint = self as any ) {
0 commit comments