@@ -25,6 +25,7 @@ export { Endpoint };
25
25
export const proxyMarker = Symbol ( "Comlink.proxy" ) ;
26
26
export const createEndpoint = Symbol ( "Comlink.endpoint" ) ;
27
27
export const releaseProxy = Symbol ( "Comlink.releaseProxy" ) ;
28
+
28
29
const throwMarker = Symbol ( "Comlink.thrown" ) ;
29
30
30
31
/**
@@ -176,51 +177,108 @@ export type Local<T> =
176
177
}
177
178
: unknown ) ;
178
179
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 ;
183
210
}
184
211
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
219
255
}
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
+ ) ;
222
268
}
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 ]
224
282
] ) ;
225
283
226
284
export function expose ( obj : any , ep : Endpoint = self as any ) {
0 commit comments