@grapes-agency/apollo-link-webworker
Advanced tools
Comparing version 1.0.0-alpha.11 to 1.0.0-alpha.12
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.0.0-alpha.12](https://github.com/grapes-agency/graphql/compare/@grapes-agency/apollo-link-webworker@1.0.0-alpha.11...@grapes-agency/apollo-link-webworker@1.0.0-alpha.12) (2021-09-13) | ||
### Features | ||
* **apollo-link-webworker:** Deep context serialization, support for AbortSignal ([eb54bcf](https://github.com/grapes-agency/graphql/commit/eb54bcf29decdbc2ed3af6d22accc3e0b2e8f126)) | ||
# [1.0.0-alpha.11](https://github.com/grapes-agency/graphql/compare/@grapes-agency/apollo-link-webworker@1.0.0-alpha.10...@grapes-agency/apollo-link-webworker@1.0.0-alpha.11) (2021-09-07) | ||
@@ -8,0 +19,0 @@ |
import { ApolloLink, Observable } from '@apollo/client'; | ||
import { wrap, proxy } from 'comlink'; | ||
import { setupRemoteObservable } from './RemoteObservable.js'; | ||
import { setupRemoteOperation } from './RemoteOperation.js'; | ||
import { registerTransferHandlers } from './transferHandlers/index.js'; | ||
setupRemoteObservable(); | ||
setupRemoteOperation(); | ||
registerTransferHandlers(); | ||
class ApolloWebWorkerLink extends ApolloLink { | ||
@@ -9,0 +7,0 @@ constructor(webWorker, options) { |
import { ApolloLink, Observable } from '@apollo/client'; | ||
import { expose } from 'comlink'; | ||
import { setupRemoteObservable } from './RemoteObservable.js'; | ||
import { setupRemoteOperation } from './RemoteOperation.js'; | ||
import { registerTransferHandlers } from './transferHandlers/index.js'; | ||
setupRemoteObservable(); | ||
setupRemoteOperation(); | ||
registerTransferHandlers(); | ||
const createAsyncLink = () => { | ||
@@ -29,2 +27,5 @@ let release = null; | ||
const maybeFixDev = () => { | ||
if (typeof global === 'undefined') { | ||
return; | ||
} | ||
const anyGlobal = global; | ||
@@ -31,0 +32,0 @@ if (!('__DEV__' in anyGlobal)) { |
@@ -5,4 +5,4 @@ 'use strict'; | ||
var Comlink = require('comlink'); | ||
var client = require('@apollo/client'); | ||
var Comlink = require('comlink'); | ||
var tslib = require('tslib'); | ||
@@ -33,54 +33,155 @@ var utils = require('@apollo/client/link/utils'); | ||
// eslint-disable-next-line handle-callback-err | ||
const objectifyError = (error) => Object.fromEntries(Object.getOwnPropertyNames(error).map(propertyName => [propertyName, error[propertyName]])); | ||
const setupRemoteObservable = () => { | ||
Comlink__namespace.transferHandlers.set('OBSERVABLE', { | ||
canHandle: (obj) => obj instanceof client.Observable, | ||
serialize: (observable) => { | ||
let activeMode = false; | ||
const debug = (mode) => { | ||
if (typeof mode === 'boolean') { | ||
activeMode = mode; | ||
} | ||
return activeMode; | ||
}; | ||
const isPlainObject = (obj) => typeof obj === 'object' && | ||
obj !== null && | ||
obj.constructor === Object && | ||
Object.prototype.toString.call(obj) === '[object Object]'; | ||
const serializeObject = (object) => { | ||
if (Array.isArray(object)) { | ||
const serializedObject = { | ||
type: 'ARRAY', | ||
value: [], | ||
}; | ||
const transferables = []; | ||
object.forEach(element => { | ||
const [serializedValue, additionalTransferables] = serializeObject(element); | ||
serializedObject.value.push(serializedValue); | ||
transferables.push(...additionalTransferables); | ||
}); | ||
return [serializedObject, transferables]; | ||
} | ||
if (isPlainObject(object)) { | ||
const serializedObject = {}; | ||
const transferables = []; | ||
for (const [key, value] of Object.entries(object)) { | ||
const [serializedValue, additionalTransferables] = serializeObject(value); | ||
serializedObject[key] = serializedValue; | ||
transferables.push(...additionalTransferables); | ||
} | ||
return [ | ||
{ | ||
type: 'OBJECT', | ||
value: serializedObject, | ||
}, | ||
transferables, | ||
]; | ||
} | ||
if (typeof object !== 'object' && typeof object !== 'function') { | ||
return [ | ||
{ | ||
type: 'RAW', | ||
value: object, | ||
}, | ||
[], | ||
]; | ||
} | ||
for (const [name, handler] of Comlink__namespace.transferHandlers) { | ||
if (handler.canHandle(object)) { | ||
const [serializedValue, transferables] = handler.serialize(object); | ||
return [ | ||
{ | ||
type: 'HANDLER', | ||
name, | ||
value: serializedValue, | ||
}, | ||
transferables, | ||
]; | ||
} | ||
} | ||
if (debug()) { | ||
console.warn('Cannot serialize object', object); | ||
} | ||
return [{ type: 'RAW', value: null }, []]; | ||
}; | ||
const deserializeObject = (serializedObject) => { | ||
if (serializedObject.type === 'RAW') { | ||
return serializedObject.value; | ||
} | ||
if (serializedObject.type === 'ARRAY') { | ||
return serializedObject.value.map(deserializeObject); | ||
} | ||
if (serializedObject.type === 'HANDLER') { | ||
const handler = Comlink__namespace.transferHandlers.get(serializedObject.name); | ||
return handler.deserialize(serializedObject.value); | ||
} | ||
const deserializedObject = {}; | ||
for (const [key, value] of Object.entries(serializedObject.value)) { | ||
deserializedObject[key] = deserializeObject(value); | ||
} | ||
return deserializedObject; | ||
}; | ||
const abortSignalTransferHandler = { | ||
canHandle: (obj) => obj instanceof AbortSignal, | ||
serialize: (signal) => { | ||
const { port1, port2 } = new MessageChannel(); | ||
signal.addEventListener('abort', () => port1.postMessage('abort')); | ||
return [port2, [port2]]; | ||
}, | ||
deserialize: (port) => { | ||
const controller = new AbortController(); | ||
port.start(); | ||
port.addEventListener('message', () => { | ||
controller.abort(); | ||
}); | ||
return controller.signal; | ||
}, | ||
}; | ||
const observableTransferHandler = { | ||
canHandle: (obj) => obj instanceof client.Observable, | ||
serialize: observable => { | ||
const { port1, port2 } = new MessageChannel(); | ||
port1.start(); | ||
port1.addEventListener('message', event => { | ||
if (!(event.data === 'subscribe' && event.ports)) { | ||
return; | ||
} | ||
const [port] = event.ports; | ||
port.start(); | ||
const subscription = observable.subscribe({ | ||
next: next => port.postMessage({ next: Object.assign(Object.assign({}, next), { errors: serializeObject(next.errors)[0] }) }), | ||
error: (error) => port.postMessage({ error }), | ||
complete: () => port.postMessage({ complete: true }), | ||
}); | ||
port.addEventListener('message', ({ data }) => { | ||
if (data === 'unsubscribe') { | ||
subscription.unsubscribe(); | ||
} | ||
}); | ||
}); | ||
return [port2, [port2]]; | ||
}, | ||
deserialize: port => { | ||
port.start(); | ||
return new client.Observable(observer => { | ||
const { port1, port2 } = new MessageChannel(); | ||
port1.start(); | ||
port1.addEventListener('message', event => { | ||
if (!(event.data === 'subscribe' && event.ports)) { | ||
return; | ||
port.postMessage('subscribe', [port2]); | ||
const handleMessage = ({ data }) => { | ||
if (data.next) { | ||
observer.next(Object.assign(Object.assign({}, data.next), { errors: deserializeObject(data.next.errors) })); | ||
} | ||
const [port] = event.ports; | ||
port.start(); | ||
const subscription = observable.subscribe({ | ||
next: next => { var _a; return port.postMessage({ next: Object.assign(Object.assign({}, next), { errors: ((_a = next.errors) === null || _a === void 0 ? void 0 : _a.map(objectifyError)) || undefined }) }); }, | ||
error: (error) => port.postMessage({ error }), | ||
complete: () => port.postMessage({ complete: true }), | ||
}); | ||
port.addEventListener('message', ({ data }) => { | ||
if (data === 'unsubscribe') { | ||
subscription.unsubscribe(); | ||
} | ||
}); | ||
}); | ||
return [port2, [port2]]; | ||
}, | ||
deserialize: (port) => { | ||
port.start(); | ||
return new client.Observable(observer => { | ||
const { port1, port2 } = new MessageChannel(); | ||
port1.start(); | ||
port.postMessage('subscribe', [port2]); | ||
const handleMessage = ({ data }) => { | ||
if (data.next) { | ||
observer.next(data.next); | ||
} | ||
else if (data.error) { | ||
observer.error(data.error); | ||
} | ||
else if (data.complete) { | ||
observer.complete(); | ||
} | ||
}; | ||
port1.addEventListener('message', handleMessage); | ||
return () => { | ||
port1.removeEventListener('message', handleMessage); | ||
port1.postMessage('unsubscribe'); | ||
}; | ||
}); | ||
}, | ||
}); | ||
else if (data.error) { | ||
observer.error(data.error); | ||
} | ||
else if (data.complete) { | ||
observer.complete(); | ||
} | ||
}; | ||
port1.addEventListener('message', handleMessage); | ||
return () => { | ||
port1.removeEventListener('message', handleMessage); | ||
port1.postMessage('unsubscribe'); | ||
}; | ||
}); | ||
}, | ||
}; | ||
@@ -95,6 +196,9 @@ | ||
} | ||
const transferableOperation = tslib.__rest(operation, ["setContext", "getContext"]); | ||
return [transferableOperation, []]; | ||
const rest = tslib.__rest(operation, ["setContext", "getContext"]); | ||
const [serializedContext, transferables] = serializeObject(operation.getContext()); | ||
const transferableOperation = Object.assign(Object.assign({}, rest), { context: serializedContext }); | ||
return [transferableOperation, transferables]; | ||
}, | ||
deserialize: transferableOperation => { | ||
deserialize: (_a) => { | ||
var { context } = _a, transferableOperation = tslib.__rest(_a, ["context"]); | ||
if (transferableOperation.operationName && operationStorage.has(transferableOperation.operationName)) { | ||
@@ -105,11 +209,13 @@ const operation = operationStorage.get(transferableOperation.operationName); | ||
} | ||
return utils.createOperation({}, transferableOperation); | ||
return utils.createOperation(deserializeObject(context), transferableOperation); | ||
}, | ||
}; | ||
const setupRemoteOperation = () => { | ||
const registerTransferHandlers = () => { | ||
Comlink__namespace.transferHandlers.set('OPERATION', operationTransferHandler); | ||
Comlink__namespace.transferHandlers.set('OBSERVABLE', observableTransferHandler); | ||
Comlink__namespace.transferHandlers.set('ABORT_SIGNAL', abortSignalTransferHandler); | ||
}; | ||
setupRemoteObservable(); | ||
setupRemoteOperation(); | ||
registerTransferHandlers(); | ||
class ApolloWebWorkerLink extends client.ApolloLink { | ||
@@ -153,4 +259,3 @@ constructor(webWorker, options) { | ||
setupRemoteObservable(); | ||
setupRemoteOperation(); | ||
registerTransferHandlers(); | ||
const createAsyncLink = () => { | ||
@@ -177,2 +282,5 @@ let release = null; | ||
const maybeFixDev = () => { | ||
if (typeof global === 'undefined') { | ||
return; | ||
} | ||
const anyGlobal = global; | ||
@@ -231,4 +339,10 @@ if (!('__DEV__' in anyGlobal)) { | ||
const registerTransferHandler = (name, tranferHandler) => Comlink__namespace.transferHandlers.set(name, tranferHandler); | ||
const setDebug = (mode) => debug(mode); | ||
exports.ApolloWebWorkerLink = ApolloWebWorkerLink; | ||
exports.createApolloWorker = createApolloWorker; | ||
exports.createWebWorkerLink = createWebWorkerLink; | ||
exports.registerTransferHandler = registerTransferHandler; | ||
exports.setDebug = setDebug; |
export * from './ApolloWebWorkerLink'; | ||
export * from './createApolloWorker'; | ||
export * from './registerTransferHandler'; | ||
export type { TransferHandler } from 'comlink'; | ||
export declare const setDebug: (mode: boolean) => boolean; |
@@ -0,3 +1,10 @@ | ||
import './utils/index.js'; | ||
export { ApolloWebWorkerLink, createWebWorkerLink } from './ApolloWebWorkerLink.js'; | ||
export { createApolloWorker } from './createApolloWorker.js'; | ||
export { registerTransferHandler } from './registerTransferHandler.js'; | ||
import { debug } from './utils/debug.js'; | ||
const setDebug = (mode) => debug(mode); | ||
export { setDebug }; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@grapes-agency/apollo-link-webworker", | ||
"version": "1.0.0-alpha.11", | ||
"version": "1.0.0-alpha.12", | ||
"description": "WebWorker for @apollo/client", | ||
@@ -25,3 +25,3 @@ "main": "./dist/index.cjs.js", | ||
}, | ||
"gitHead": "4cfb22277182861d147408ec85c49eafec3fdc38" | ||
"gitHead": "90e47ae99844f88378f1c41ad2d92e8629969555" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
57028
39
735