webext-redux
Advanced tools
Comparing version 2.1.9 to 3.0.0-mv3.0
@@ -712,5 +712,8 @@ (function (global, factory) { | ||
// from the Proxy Stores to background | ||
var DISPATCH_TYPE = 'chromex.dispatch'; // Message type for state update events from | ||
var DISPATCH_TYPE = 'chromex.dispatch'; // Message type for fetching current state from | ||
// background to Proxy Stores | ||
var FETCH_STATE_TYPE = 'chromex.fetch_state'; // Message type for state update events from | ||
// background to Proxy Stores | ||
var STATE_TYPE = 'chromex.state'; // Message type for state patch events from | ||
@@ -899,3 +902,2 @@ // background to Proxy Stores | ||
state: {}, | ||
extensionId: null, | ||
serializer: noop, | ||
@@ -911,3 +913,3 @@ deserializer: noop, | ||
* Creates a new Proxy store | ||
* @param {object} options An object of form {portName, state, extensionId, serializer, deserializer, diffStrategy}, where `portName` is a required string and defines the name of the port for state transition changes, `state` is the initial state of this store (default `{}`) `extensionId` is the extension id as defined by browserAPI when extension is loaded (default `''`), `serializer` is a function to serialize outgoing message payloads (default is passthrough), `deserializer` is a function to deserialize incoming message payloads (default is passthrough), and patchStrategy is one of the included patching strategies (default is shallow diff) or a custom patching function. | ||
* @param {object} options An object of form {portName, state, serializer, deserializer, diffStrategy}, where `portName` is a required string and defines the name of the port for state transition changes, `state` is the initial state of this store (default `{}`) `serializer` is a function to serialize outgoing message payloads (default is passthrough), `deserializer` is a function to deserialize incoming message payloads (default is passthrough), and patchStrategy is one of the included patching strategies (default is shallow diff) or a custom patching function. | ||
*/ | ||
@@ -922,4 +924,2 @@ function Store() { | ||
state = _ref$state === void 0 ? defaultOpts.state : _ref$state, | ||
_ref$extensionId = _ref.extensionId, | ||
extensionId = _ref$extensionId === void 0 ? defaultOpts.extensionId : _ref$extensionId, | ||
_ref$serializer = _ref.serializer, | ||
@@ -956,23 +956,19 @@ serializer = _ref$serializer === void 0 ? defaultOpts.serializer : _ref$serializer, | ||
this.browserAPI = getBrowserAPI(); | ||
this.extensionId = extensionId; // keep the extensionId as an instance variable | ||
this.initializeStore = this.initializeStore.bind(this); // We request the latest available state data to initialise our store | ||
this.port = this.browserAPI.runtime.connect(this.extensionId, { | ||
name: portName | ||
}); | ||
this.safetyHandler = this.safetyHandler.bind(this); | ||
if (this.browserAPI.runtime.onMessage) { | ||
this.safetyMessage = this.browserAPI.runtime.onMessage.addListener(this.safetyHandler); | ||
} | ||
this.browserAPI.runtime.sendMessage({ | ||
type: FETCH_STATE_TYPE, | ||
portName: portName | ||
}, undefined, this.initializeStore); | ||
this.deserializer = deserializer; | ||
this.serializedPortListener = withDeserializer(deserializer)(function () { | ||
var _this$port$onMessage; | ||
var _this$browserAPI$runt; | ||
return (_this$port$onMessage = _this.port.onMessage).addListener.apply(_this$port$onMessage, arguments); | ||
return (_this$browserAPI$runt = _this.browserAPI.runtime.onMessage).addListener.apply(_this$browserAPI$runt, arguments); | ||
}); | ||
this.serializedMessageSender = withSerializer(serializer)(function () { | ||
var _this$browserAPI$runt; | ||
var _this$browserAPI$runt2; | ||
return (_this$browserAPI$runt = _this.browserAPI.runtime).sendMessage.apply(_this$browserAPI$runt, arguments); | ||
}, 1); | ||
return (_this$browserAPI$runt2 = _this.browserAPI.runtime).sendMessage.apply(_this$browserAPI$runt2, arguments); | ||
}, 0); | ||
this.listeners = []; | ||
@@ -983,21 +979,23 @@ this.state = state; | ||
this.serializedPortListener(function (message) { | ||
switch (message.type) { | ||
case STATE_TYPE: | ||
_this.replaceState(message.payload); | ||
if (message.portName === _this.portName) { | ||
switch (message.type) { | ||
case STATE_TYPE: | ||
_this.replaceState(message.payload); | ||
if (!_this.readyResolved) { | ||
_this.readyResolved = true; | ||
if (!_this.readyResolved) { | ||
_this.readyResolved = true; | ||
_this.readyResolve(); | ||
} | ||
_this.readyResolve(); | ||
} | ||
break; | ||
break; | ||
case PATCH_STATE_TYPE: | ||
_this.patchState(message.payload); | ||
case PATCH_STATE_TYPE: | ||
_this.patchState(message.payload); | ||
break; | ||
break; | ||
default: // do nothing | ||
default: // do nothing | ||
} | ||
} | ||
@@ -1100,3 +1098,3 @@ }); | ||
return new Promise(function (resolve, reject) { | ||
_this3.serializedMessageSender(_this3.extensionId, { | ||
_this3.serializedMessageSender({ | ||
type: DISPATCH_TYPE, | ||
@@ -1127,7 +1125,6 @@ portName: _this3.portName, | ||
}, { | ||
key: "safetyHandler", | ||
value: function safetyHandler(message) { | ||
if (message.action === 'storeReady' && message.portName === this.portName) { | ||
// Remove Saftey Listener | ||
this.browserAPI.runtime.onMessage.removeListener(this.safetyHandler); // Resolve if readyPromise has not been resolved. | ||
key: "initializeStore", | ||
value: function initializeStore(message) { | ||
if (message && message.type === FETCH_STATE_TYPE) { | ||
this.replaceState(message.payload); // Resolve if readyPromise has not been resolved. | ||
@@ -1226,2 +1223,23 @@ if (!this.readyResolved) { | ||
var createDeferredListener = function createDeferredListener() { | ||
var resolve = function resolve() {}; | ||
var fnPromise = new Promise(function (resolve_) { | ||
return resolve = resolve_; | ||
}); | ||
var listener = function listener(message, sender, sendResponse) { | ||
fnPromise.then(function (fn) { | ||
fn(message, sender, sendResponse); | ||
}); // Allow response to be async | ||
return true; | ||
}; | ||
return { | ||
setListener: resolve, | ||
listener: listener | ||
}; | ||
}; | ||
/** | ||
@@ -1241,3 +1259,3 @@ * Responder for promisified results | ||
}).catch(function (err) { | ||
console.error('error dispatching result:', err); | ||
console.error("error dispatching result:", err); | ||
send({ | ||
@@ -1258,83 +1276,146 @@ error: err.message, | ||
/** | ||
* Wraps a Redux store so that proxy stores can connect to it. | ||
* @typedef {function} WrapStore | ||
* @param {Object} store A Redux store | ||
* @param {Object} options An object of form {portName, dispatchResponder, serializer, deserializer}, where `portName` is a required string and defines the name of the port for state transition changes, `dispatchResponder` is a function that takes the result of a store dispatch and optionally implements custom logic for responding to the original dispatch message,`serializer` is a function to serialize outgoing message payloads (default is passthrough), `deserializer` is a function to deserialize incoming message payloads (default is passthrough), and diffStrategy is one of the included diffing strategies (default is shallow diff) or a custom diffing function. | ||
* @param {Object} options | ||
* @param {string} options.portName The name of the port for state transition | ||
* changes. | ||
* @param {function} options.dispatchResponder A function that takes the result | ||
* of a store dispatch and optionally implements custom logic for responding to | ||
* the original dispatch message. | ||
* @param {function} options.serializer A function to serialize outgoing message | ||
* payloads (default is passthrough). | ||
* @param {function} options.deserializer A function to deserialize incoming | ||
* message payloads (default is passthrough). | ||
* @param {function} options.diffStrategy A function to diff the previous state | ||
* and the new state (default is shallow diff). | ||
*/ | ||
var wrapStore = (function (store) { | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts$1, | ||
_ref$portName = _ref.portName, | ||
portName = _ref$portName === void 0 ? defaultOpts$1.portName : _ref$portName, | ||
_ref$dispatchResponde = _ref.dispatchResponder, | ||
dispatchResponder = _ref$dispatchResponde === void 0 ? defaultOpts$1.dispatchResponder : _ref$dispatchResponde, | ||
_ref$serializer = _ref.serializer, | ||
serializer = _ref$serializer === void 0 ? defaultOpts$1.serializer : _ref$serializer, | ||
_ref$deserializer = _ref.deserializer, | ||
deserializer = _ref$deserializer === void 0 ? defaultOpts$1.deserializer : _ref$deserializer, | ||
_ref$diffStrategy = _ref.diffStrategy, | ||
diffStrategy = _ref$diffStrategy === void 0 ? defaultOpts$1.diffStrategy : _ref$diffStrategy; | ||
/** | ||
* Wraps a Redux store so that proxy stores can connect to it. This function | ||
* must be called synchronously when the extension loads to avoid dropping | ||
* messages that woke the service worker. | ||
* @return {WrapStore} The wrapStore function that accepts a Redux store and | ||
* options. See {@link WrapStore}. | ||
*/ | ||
if (!portName) { | ||
throw new Error('portName is required in options'); | ||
} | ||
var wrapStore = (function () { | ||
var browserAPI = getBrowserAPI(); // Setup message listeners synchronously to avoid dropping messages if the | ||
// extension is woken by a message. | ||
if (typeof serializer !== 'function') { | ||
throw new Error('serializer must be a function'); | ||
} | ||
var stateProviderListener = createDeferredListener(); | ||
var actionListener = createDeferredListener(); | ||
browserAPI.runtime.onMessage.addListener(stateProviderListener.listener); | ||
browserAPI.runtime.onMessage.addListener(actionListener.listener); | ||
return function (store) { | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts$1, | ||
_ref$portName = _ref.portName, | ||
portName = _ref$portName === void 0 ? defaultOpts$1.portName : _ref$portName, | ||
_ref$dispatchResponde = _ref.dispatchResponder, | ||
dispatchResponder = _ref$dispatchResponde === void 0 ? defaultOpts$1.dispatchResponder : _ref$dispatchResponde, | ||
_ref$serializer = _ref.serializer, | ||
serializer = _ref$serializer === void 0 ? defaultOpts$1.serializer : _ref$serializer, | ||
_ref$deserializer = _ref.deserializer, | ||
deserializer = _ref$deserializer === void 0 ? defaultOpts$1.deserializer : _ref$deserializer, | ||
_ref$diffStrategy = _ref.diffStrategy, | ||
diffStrategy = _ref$diffStrategy === void 0 ? defaultOpts$1.diffStrategy : _ref$diffStrategy; | ||
if (typeof deserializer !== 'function') { | ||
throw new Error('deserializer must be a function'); | ||
} | ||
if (!portName) { | ||
throw new Error("portName is required in options"); | ||
} | ||
if (typeof diffStrategy !== 'function') { | ||
throw new Error('diffStrategy must be one of the included diffing strategies or a custom diff function'); | ||
} | ||
if (typeof serializer !== "function") { | ||
throw new Error("serializer must be a function"); | ||
} | ||
var browserAPI = getBrowserAPI(); | ||
/** | ||
* Respond to dispatches from UI components | ||
*/ | ||
if (typeof deserializer !== "function") { | ||
throw new Error("deserializer must be a function"); | ||
} | ||
var dispatchResponse = function dispatchResponse(request, sender, sendResponse) { | ||
if (request.type === DISPATCH_TYPE && request.portName === portName) { | ||
var action = Object.assign({}, request.payload, { | ||
_sender: sender | ||
}); | ||
var dispatchResult = null; | ||
if (typeof diffStrategy !== "function") { | ||
throw new Error("diffStrategy must be one of the included diffing strategies or a custom diff function"); | ||
} | ||
/** | ||
* Respond to dispatches from UI components | ||
*/ | ||
try { | ||
dispatchResult = store.dispatch(action); | ||
} catch (e) { | ||
dispatchResult = Promise.reject(e.message); | ||
console.error(e); | ||
var dispatchResponse = function dispatchResponse(request, sender, sendResponse) { | ||
if (request.type === DISPATCH_TYPE && request.portName === portName) { | ||
var action = Object.assign({}, request.payload, { | ||
_sender: sender | ||
}); | ||
var dispatchResult = null; | ||
try { | ||
dispatchResult = store.dispatch(action); | ||
} catch (e) { | ||
dispatchResult = Promise.reject(e.message); | ||
console.error(e); | ||
} | ||
dispatchResponder(dispatchResult, sendResponse); | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Setup for state updates | ||
*/ | ||
dispatchResponder(dispatchResult, sendResponse); | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Setup for state updates | ||
*/ | ||
var serializedMessagePoster = withSerializer(serializer)(function () { | ||
var _browserAPI$runtime; | ||
var connectState = function connectState(port) { | ||
if (port.name !== portName) { | ||
return; | ||
} | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var serializedMessagePoster = withSerializer(serializer)(function () { | ||
return port.postMessage.apply(port, arguments); | ||
var onErrorCallback = function onErrorCallback() { | ||
if (browserAPI.runtime.lastError) ; | ||
}; | ||
(_browserAPI$runtime = browserAPI.runtime).sendMessage.apply(_browserAPI$runtime, args.concat([onErrorCallback])); // We will broadcast state changes to all tabs to sync state across content scripts | ||
return browserAPI.tabs.query({}, function (tabs) { | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = tabs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _browserAPI$tabs; | ||
var tab = _step.value; | ||
(_browserAPI$tabs = browserAPI.tabs).sendMessage.apply(_browserAPI$tabs, [tab.id].concat(args, [onErrorCallback])); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
var prevState = store.getState(); | ||
var currentState = store.getState(); | ||
var patchState = function patchState() { | ||
var state = store.getState(); | ||
var diff = diffStrategy(prevState, state); | ||
var newState = store.getState(); | ||
var diff = diffStrategy(currentState, newState); | ||
if (diff.length) { | ||
prevState = state; | ||
currentState = newState; | ||
serializedMessagePoster({ | ||
type: PATCH_STATE_TYPE, | ||
payload: diff | ||
payload: diff, | ||
portName: portName // Notifying what extension is broadcasting the state changes | ||
}); | ||
@@ -1345,94 +1426,36 @@ } | ||
var unsubscribe = store.subscribe(patchState); // when the port disconnects, unsubscribe the sendState listener | ||
store.subscribe(patchState); // Send store's initial state through port | ||
port.onDisconnect.addListener(unsubscribe); // Send store's initial state through port | ||
serializedMessagePoster({ | ||
type: STATE_TYPE, | ||
payload: prevState | ||
payload: currentState, | ||
portName: portName // Notifying what extension is broadcasting the state changes | ||
}); | ||
}; | ||
var withPayloadDeserializer = withDeserializer(deserializer); | ||
var withPayloadDeserializer = withDeserializer(deserializer); | ||
var shouldDeserialize = function shouldDeserialize(request) { | ||
return request.type === DISPATCH_TYPE && request.portName === portName; | ||
}; | ||
/** | ||
* State provider for content-script initialization | ||
*/ | ||
var shouldDeserialize = function shouldDeserialize(request) { | ||
return request.type === DISPATCH_TYPE && request.portName === portName; | ||
}; | ||
/** | ||
* Setup action handler | ||
*/ | ||
stateProviderListener.setListener(function (request, sender, sendResponse) { | ||
var state = store.getState(); | ||
withPayloadDeserializer(function () { | ||
var _browserAPI$runtime$o; | ||
return (_browserAPI$runtime$o = browserAPI.runtime.onMessage).addListener.apply(_browserAPI$runtime$o, arguments); | ||
})(dispatchResponse, shouldDeserialize); | ||
/** | ||
* Setup external action handler | ||
*/ | ||
if (browserAPI.runtime.onMessageExternal) { | ||
withPayloadDeserializer(function () { | ||
var _browserAPI$runtime$o2; | ||
return (_browserAPI$runtime$o2 = browserAPI.runtime.onMessageExternal).addListener.apply(_browserAPI$runtime$o2, arguments); | ||
})(dispatchResponse, shouldDeserialize); | ||
} else { | ||
console.warn('runtime.onMessageExternal is not supported'); | ||
} | ||
/** | ||
* Setup extended connection | ||
*/ | ||
browserAPI.runtime.onConnect.addListener(connectState); | ||
/** | ||
* Setup extended external connection | ||
*/ | ||
if (browserAPI.runtime.onConnectExternal) { | ||
browserAPI.runtime.onConnectExternal.addListener(connectState); | ||
} else { | ||
console.warn('runtime.onConnectExternal is not supported'); | ||
} | ||
/** | ||
* Safety message to tabs for content scripts | ||
*/ | ||
browserAPI.tabs.query({}, function (tabs) { | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = tabs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var tab = _step.value; | ||
browserAPI.tabs.sendMessage(tab.id, { | ||
action: 'storeReady', | ||
portName: portName | ||
}, function () { | ||
if (chrome.runtime.lastError) {// do nothing - errors can be present | ||
// if no content script exists on reciever | ||
} | ||
if (request.type === FETCH_STATE_TYPE && request.portName === portName) { | ||
sendResponse({ | ||
type: FETCH_STATE_TYPE, | ||
payload: state | ||
}); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
}); // For non-tab based | ||
// TODO: Find use case for this. Ommiting until then. | ||
// browserAPI.runtime.sendMessage(null, {action: 'storeReady'}); | ||
}); | ||
/** | ||
* Setup action handler | ||
*/ | ||
withPayloadDeserializer(actionListener.setListener)(dispatchResponse, shouldDeserialize); | ||
}; | ||
}); | ||
@@ -1464,3 +1487,3 @@ | ||
exports.applyMiddleware = applyMiddleware; | ||
exports.wrapStore = wrapStore; | ||
exports.createWrapStore = wrapStore; | ||
@@ -1467,0 +1490,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).WebextRedux={})}(this,(function(e){"use strict";function t(e,t){for(var r=0;t.length>r;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function r(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e){for(var t=1;arguments.length>t;t++){var n=null!=arguments[t]?arguments[t]:{},o=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(n).filter((function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable})))),o.forEach((function(t){r(e,t,n[t])}))}return e}function o(e){return function(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);e.length>t;t++)r[t]=e[t];return r}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var i=9007199254740991,a="[object Arguments]",s="[object Function]",u="[object GeneratorFunction]",c=/^(?:0|[1-9]\d*)$/;function l(e,t,r){switch(r.length){case 0:return e.call(t);case 1:return e.call(t,r[0]);case 2:return e.call(t,r[0],r[1]);case 3:return e.call(t,r[0],r[1],r[2])}return e.apply(t,r)}var f=Object.prototype,d=f.hasOwnProperty,p=f.toString,h=f.propertyIsEnumerable,y=Math.max;function v(e,t){var r=P(e)||function(e){return function(e){return function(e){return!!e&&"object"==typeof e}(e)&&j(e)}(e)&&d.call(e,"callee")&&(!h.call(e,"callee")||p.call(e)==a)}(e)?function(e,t){for(var r=-1,n=Array(e);++r<e;)n[r]=t(r);return n}(e.length,String):[],n=r.length,o=!!n;for(var i in e)!t&&!d.call(e,i)||o&&("length"==i||b(i,n))||r.push(i);return r}function g(e,t,r){var n=e[t];d.call(e,t)&&w(n,r)&&(void 0!==r||t in e)||(e[t]=r)}function m(e){if(!A(e))return function(e){var t=[];if(null!=e)for(var r in Object(e))t.push(r);return t}(e);var t,r,n=(t=e)===("function"==typeof(r=t&&t.constructor)&&r.prototype||f),o=[];for(var i in e)("constructor"!=i||!n&&d.call(e,i))&&o.push(i);return o}function b(e,t){return!!(t=null==t?i:t)&&("number"==typeof e||c.test(e))&&e>-1&&e%1==0&&t>e}function w(e,t){return e===t||e!=e&&t!=t}var E,S,x,P=Array.isArray;function j(e){return null!=e&&function(e){return"number"==typeof e&&e>-1&&e%1==0&&i>=e}(e.length)&&!function(e){var t=A(e)?p.call(e):"";return t==s||t==u}(e)}function A(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var O=(E=function(e,t){!function(e,t,r,n){r||(r={});for(var o=-1,i=t.length;++o<i;){var a=t[o],s=n?n(r[a],e[a],a,r,e):void 0;g(r,a,void 0===s?e[a]:s)}}(t,function(e){return j(e)?v(e,!0):m(e)}(t),e)},S=function(e,t){var r=-1,n=t.length,o=n>1?t[n-1]:void 0,i=n>2?t[2]:void 0;for(o=E.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(e,t,r){if(!A(r))return!1;var n=typeof t;return!!("number"==n?j(r)&&b(t,r.length):"string"==n&&t in r)&&w(r[t],e)}(t[0],t[1],i)&&(o=3>n?void 0:o,n=1),e=Object(e);++r<n;){var a=t[r];a&&E(e,a,r,o)}return e},x=y(void 0===x?S.length-1:x,0),function(){for(var e=arguments,t=-1,r=y(e.length-x,0),n=Array(r);++t<r;)n[t]=e[x+t];t=-1;for(var o=Array(x+1);++t<x;)o[t]=e[t];return o[x]=n,l(S,this,o)}),k="chromex.state",z="chromex.patch_state",M=function(e){return e},I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:M;return n({},e,e.payload?{payload:t(e.payload)}:{})},N=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:M,r=arguments.length>2?arguments[2]:void 0;return r?function(n){for(var o=arguments.length,i=Array(o>1?o-1:0),a=1;o>a;a++)i[a-1]=arguments[a];return r.apply(void 0,[n].concat(i))?e.apply(void 0,[I(n,t)].concat(i)):e.apply(void 0,[n].concat(i))}:function(r){for(var n=arguments.length,o=Array(n>1?n-1:0),i=1;n>i;i++)o[i-1]=arguments[i];return e.apply(void 0,[I(r,t)].concat(o))}},R=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:M;return function(t){return function(r,n){return t(N(r,e,n))}}},L=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:M;return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return function(){for(var n=arguments.length,o=Array(n),i=0;n>i;i++)o[i]=arguments[i];if(r>=o.length)throw Error("Message in request could not be serialized. "+"Expected message in position ".concat(r," but only received ").concat(o.length," args."));return o[r]=I(o[r],e),t.apply(void 0,o)}}},_="updated",C="removed";function H(){var e;try{e=self.chrome||self.browser||browser}catch(t){e=browser}if(!e)throw Error("Browser API is not present");return e}var q="\nLooks like there is an error in the background page. You might want to inspect your background page for more details.\n",D={portName:"chromex.port_name",state:{},extensionId:null,serializer:M,deserializer:M,patchStrategy:function(e,t){var r=Object.assign({},e);return t.forEach((function(e){var t=e.key,n=e.value;switch(e.change){case _:r[t]=n;break;case C:Reflect.deleteProperty(r,t)}})),r}};function F(){for(var e=arguments.length,t=Array(e),r=0;e>r;r++)t[r]=arguments[r];return 0===t.length?function(e){return e}:1===t.length?t[0]:t.reduce((function(e,t){return function(){return e(t.apply(void 0,arguments))}}))}var T={portName:"chromex.port_name",dispatchResponder:function(e,t){Promise.resolve(e).then((function(e){t({error:null,value:e})})).catch((function(e){console.error("error dispatching result:",e),t({error:e.message,value:null})}))},serializer:M,deserializer:M,diffStrategy:function(e,t){var r=[];return Object.keys(t).forEach((function(n){e[n]!==t[n]&&r.push({key:n,value:t[n],change:_})})),Object.keys(e).forEach((function(e){t.hasOwnProperty(e)||r.push({key:e,change:C})})),r}};e.Store=function(){function e(){var t=this,r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:D,n=r.portName,o=void 0===n?D.portName:n,i=r.state,a=void 0===i?D.state:i,s=r.extensionId,u=void 0===s?D.extensionId:s,c=r.serializer,l=void 0===c?D.serializer:c,f=r.deserializer,d=void 0===f?D.deserializer:f,p=r.patchStrategy,h=void 0===p?D.patchStrategy:p;if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),!o)throw Error("portName is required in options");if("function"!=typeof l)throw Error("serializer must be a function");if("function"!=typeof d)throw Error("deserializer must be a function");if("function"!=typeof h)throw Error("patchStrategy must be one of the included patching strategies or a custom patching function");this.portName=o,this.readyResolved=!1,this.readyPromise=new Promise((function(e){return t.readyResolve=e})),this.browserAPI=H(),this.extensionId=u,this.port=this.browserAPI.runtime.connect(this.extensionId,{name:o}),this.safetyHandler=this.safetyHandler.bind(this),this.browserAPI.runtime.onMessage&&(this.safetyMessage=this.browserAPI.runtime.onMessage.addListener(this.safetyHandler)),this.serializedPortListener=R(d)((function(){var e;return(e=t.port.onMessage).addListener.apply(e,arguments)})),this.serializedMessageSender=L(l)((function(){var e;return(e=t.browserAPI.runtime).sendMessage.apply(e,arguments)}),1),this.listeners=[],this.state=a,this.patchStrategy=h,this.serializedPortListener((function(e){switch(e.type){case k:t.replaceState(e.payload),t.readyResolved||(t.readyResolved=!0,t.readyResolve());break;case z:t.patchState(e.payload)}})),this.dispatch=this.dispatch.bind(this)}var r,n,o;return r=e,(n=[{key:"ready",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return null!==e?this.readyPromise.then(e):this.readyPromise}},{key:"subscribe",value:function(e){var t=this;return this.listeners.push(e),function(){t.listeners=t.listeners.filter((function(t){return t!==e}))}}},{key:"patchState",value:function(e){this.state=this.patchStrategy(this.state,e),this.listeners.forEach((function(e){return e()}))}},{key:"replaceState",value:function(e){this.state=e,this.listeners.forEach((function(e){return e()}))}},{key:"getState",value:function(){return this.state}},{key:"replaceReducer",value:function(){}},{key:"dispatch",value:function(e){var t=this;return new Promise((function(r,n){t.serializedMessageSender(t.extensionId,{type:"chromex.dispatch",portName:t.portName,payload:e},null,(function(e){if(e){var o=e.error,i=e.value;if(o){var a=Error("".concat(q).concat(o));n(O(a,o))}else r(i&&i.payload)}else{var s=t.browserAPI.runtime.lastError,u=Error("".concat(q).concat(s));n(O(u,s))}}))}))}},{key:"safetyHandler",value:function(e){"storeReady"===e.action&&e.portName===this.portName&&(this.browserAPI.runtime.onMessage.removeListener(this.safetyHandler),this.readyResolved||(this.readyResolved=!0,this.readyResolve()))}}])&&t(r.prototype,n),o&&t(r,o),e}(),e.alias=function(e){return function(){return function(t){return function(r){var n=e[r.type];return t(n?n(r):r)}}}},e.applyMiddleware=function(e){for(var t=arguments.length,r=Array(t>1?t-1:0),n=1;t>n;n++)r[n-1]=arguments[n];var i=function(){throw Error("Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch.")},a={getState:e.getState.bind(e),dispatch:function(){return i.apply(void 0,arguments)}};return r=(r||[]).map((function(e){return e(a)})),i=F.apply(void 0,o(r))(e.dispatch),e.dispatch=i,e},e.wrapStore=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:T,r=t.portName,n=void 0===r?T.portName:r,o=t.dispatchResponder,i=void 0===o?T.dispatchResponder:o,a=t.serializer,s=void 0===a?T.serializer:a,u=t.deserializer,c=void 0===u?T.deserializer:u,l=t.diffStrategy,f=void 0===l?T.diffStrategy:l;if(!n)throw Error("portName is required in options");if("function"!=typeof s)throw Error("serializer must be a function");if("function"!=typeof c)throw Error("deserializer must be a function");if("function"!=typeof f)throw Error("diffStrategy must be one of the included diffing strategies or a custom diff function");var d=H(),p=function(t,r,o){if("chromex.dispatch"===t.type&&t.portName===n){var a=Object.assign({},t.payload,{_sender:r}),s=null;try{s=e.dispatch(a)}catch(e){s=Promise.reject(e.message),console.error(e)}return i(s,o),!0}},h=function(t){if(t.name===n){var r=L(s)((function(){return t.postMessage.apply(t,arguments)})),o=e.getState(),i=e.subscribe((function(){var t=e.getState(),n=f(o,t);n.length&&(o=t,r({type:z,payload:n}))}));t.onDisconnect.addListener(i),r({type:k,payload:o})}},y=R(c),v=function(e){return"chromex.dispatch"===e.type&&e.portName===n};y((function(){var e;return(e=d.runtime.onMessage).addListener.apply(e,arguments)}))(p,v),d.runtime.onMessageExternal?y((function(){var e;return(e=d.runtime.onMessageExternal).addListener.apply(e,arguments)}))(p,v):console.warn("runtime.onMessageExternal is not supported"),d.runtime.onConnect.addListener(h),d.runtime.onConnectExternal?d.runtime.onConnectExternal.addListener(h):console.warn("runtime.onConnectExternal is not supported"),d.tabs.query({},(function(e){var t=!0,r=!1,o=void 0;try{for(var i,a=e[Symbol.iterator]();!(t=(i=a.next()).done);t=!0){d.tabs.sendMessage(i.value.id,{action:"storeReady",portName:n},(function(){chrome}))}}catch(e){r=!0,o=e}finally{try{t||null==a.return||a.return()}finally{if(r)throw o}}}))},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).WebextRedux={})}(this,(function(e){"use strict";function t(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){for(var r=0;t.length>r;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e){for(var t=1;arguments.length>t;t++){var r=null!=arguments[t]?arguments[t]:{},o=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(r).filter((function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})))),o.forEach((function(t){n(e,t,r[t])}))}return e}function i(e){return function(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);e.length>t;t++)r[t]=e[t];return r}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var a=/^(?:0|[1-9]\d*)$/;function c(e,t,r){switch(r.length){case 0:return e.call(t);case 1:return e.call(t,r[0]);case 2:return e.call(t,r[0],r[1]);case 3:return e.call(t,r[0],r[1],r[2])}return e.apply(t,r)}var u=Object.prototype,s=u.hasOwnProperty,l=u.toString,f=u.propertyIsEnumerable,p=Math.max;function h(e,t){var r=S(e)||function(e){return function(e){return function(e){return!!e&&"object"==typeof e}(e)&&z(e)}(e)&&s.call(e,"callee")&&(!f.call(e,"callee")||"[object Arguments]"==l.call(e))}(e)?function(e,t){for(var r=-1,n=Array(e);++r<e;)n[r]=t(r);return n}(e.length,String):[],n=r.length,o=!!n;for(var i in e)!t&&!s.call(e,i)||o&&("length"==i||v(i,n))||r.push(i);return r}function d(e,t,r){var n=e[t];s.call(e,t)&&g(n,r)&&(void 0!==r||t in e)||(e[t]=r)}function y(e){if(!P(e))return function(e){var t=[];if(null!=e)for(var r in Object(e))t.push(r);return t}(e);var t,r,n=(t=e)===("function"==typeof(r=t&&t.constructor)&&r.prototype||u),o=[];for(var i in e)("constructor"!=i||!n&&s.call(e,i))&&o.push(i);return o}function v(e,t){return!!(t=null==t?9007199254740991:t)&&("number"==typeof e||a.test(e))&&e>-1&&e%1==0&&t>e}function g(e,t){return e===t||e!=e&&t!=t}var m,b,w,S=Array.isArray;function z(e){return null!=e&&function(e){return"number"==typeof e&&e>-1&&e%1==0&&9007199254740991>=e}(e.length)&&!function(e){var t=P(e)?l.call(e):"";return"[object Function]"==t||"[object GeneratorFunction]"==t}(e)}function P(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var j=(m=function(e,t){!function(e,t,r,n){r||(r={});for(var o=-1,i=t.length;++o<i;){var a=t[o],c=n?n(r[a],e[a],a,r,e):void 0;d(r,a,void 0===c?e[a]:c)}}(t,function(e){return z(e)?h(e,!0):y(e)}(t),e)},b=function(e,t){var r=-1,n=t.length,o=n>1?t[n-1]:void 0,i=n>2?t[2]:void 0;for(o=m.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(e,t,r){if(!P(r))return!1;var n=typeof t;return!!("number"==n?z(r)&&v(t,r.length):"string"==n&&t in r)&&g(r[t],e)}(t[0],t[1],i)&&(o=3>n?void 0:o,n=1),e=Object(e);++r<n;){var a=t[r];a&&m(e,a,r,o)}return e},w=p(void 0===w?b.length-1:w,0),function(){for(var e=arguments,t=-1,r=p(e.length-w,0),n=Array(r);++t<r;)n[t]=e[w+t];t=-1;for(var o=Array(w+1);++t<w;)o[t]=e[t];return o[w]=n,c(b,this,o)}),E=function(e){return e},A=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:E;return o({},e,e.payload?{payload:t(e.payload)}:{})},O=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:E,r=arguments.length>2?arguments[2]:void 0;return r?function(n){for(var o=arguments.length,i=Array(o>1?o-1:0),a=1;o>a;a++)i[a-1]=arguments[a];return r.apply(void 0,[n].concat(i))?e.apply(void 0,[A(n,t)].concat(i)):e.apply(void 0,[n].concat(i))}:function(r){for(var n=arguments.length,o=Array(n>1?n-1:0),i=1;n>i;i++)o[i-1]=arguments[i];return e.apply(void 0,[A(r,t)].concat(o))}},k=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:E;return function(t){return function(r,n){return t(O(r,e,n))}}},x=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:E;return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return function(){for(var n=arguments.length,o=Array(n),i=0;n>i;i++)o[i]=arguments[i];if(r>=o.length)throw Error("Message in request could not be serialized. "+"Expected message in position ".concat(r," but only received ").concat(o.length," args."));return o[r]=A(o[r],e),t.apply(void 0,o)}}};function N(){var e;try{e=self.chrome||self.browser||browser}catch(t){e=browser}if(!e)throw Error("Browser API is not present");return e}var R="\nLooks like there is an error in the background page. You might want to inspect your background page for more details.\n",M={portName:"chromex.port_name",state:{},serializer:E,deserializer:E,patchStrategy:function(e,t){var r=Object.assign({},e);return t.forEach((function(e){var t=e.key,n=e.value;switch(e.change){case"updated":r[t]=n;break;case"removed":Reflect.deleteProperty(r,t)}})),r}};function _(){for(var e=arguments.length,t=Array(e),r=0;e>r;r++)t[r]=arguments[r];return 0===t.length?function(e){return e}:1===t.length?t[0]:t.reduce((function(e,t){return function(){return e(t.apply(void 0,arguments))}}))}var L=function(){var e=function(){},t=new Promise((function(t){return e=t}));return{setListener:e,listener:function(e,r,n){return t.then((function(t){t(e,r,n)})),!0}}},I={portName:"chromex.port_name",dispatchResponder:function(e,t){Promise.resolve(e).then((function(e){t({error:null,value:e})})).catch((function(e){console.error("error dispatching result:",e),t({error:e.message,value:null})}))},serializer:E,deserializer:E,diffStrategy:function(e,t){var r=[];return Object.keys(t).forEach((function(n){e[n]!==t[n]&&r.push({key:n,value:t[n],change:"updated"})})),Object.keys(e).forEach((function(e){t.hasOwnProperty(e)||r.push({key:e,change:"removed"})})),r}};e.Store=function(){function e(){var r=this,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:M,o=n.portName,i=void 0===o?M.portName:o,a=n.state,c=void 0===a?M.state:a,u=n.serializer,s=void 0===u?M.serializer:u,l=n.deserializer,f=void 0===l?M.deserializer:l,p=n.patchStrategy,h=void 0===p?M.patchStrategy:p;if(t(this,e),!i)throw Error("portName is required in options");if("function"!=typeof s)throw Error("serializer must be a function");if("function"!=typeof f)throw Error("deserializer must be a function");if("function"!=typeof h)throw Error("patchStrategy must be one of the included patching strategies or a custom patching function");this.portName=i,this.readyResolved=!1,this.readyPromise=new Promise((function(e){return r.readyResolve=e})),this.browserAPI=N(),this.initializeStore=this.initializeStore.bind(this),this.browserAPI.runtime.sendMessage({type:"chromex.fetch_state",portName:i},void 0,this.initializeStore),this.deserializer=f,this.serializedPortListener=k(f)((function(){var e;return(e=r.browserAPI.runtime.onMessage).addListener.apply(e,arguments)})),this.serializedMessageSender=x(s)((function(){var e;return(e=r.browserAPI.runtime).sendMessage.apply(e,arguments)}),0),this.listeners=[],this.state=c,this.patchStrategy=h,this.serializedPortListener((function(e){if(e.portName===r.portName)switch(e.type){case"chromex.state":r.replaceState(e.payload),r.readyResolved||(r.readyResolved=!0,r.readyResolve());break;case"chromex.patch_state":r.patchState(e.payload)}})),this.dispatch=this.dispatch.bind(this)}var n,o,i;return n=e,(o=[{key:"ready",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return null!==e?this.readyPromise.then(e):this.readyPromise}},{key:"subscribe",value:function(e){var t=this;return this.listeners.push(e),function(){t.listeners=t.listeners.filter((function(t){return t!==e}))}}},{key:"patchState",value:function(e){this.state=this.patchStrategy(this.state,e),this.listeners.forEach((function(e){return e()}))}},{key:"replaceState",value:function(e){this.state=e,this.listeners.forEach((function(e){return e()}))}},{key:"getState",value:function(){return this.state}},{key:"replaceReducer",value:function(){}},{key:"dispatch",value:function(e){var t=this;return new Promise((function(r,n){t.serializedMessageSender({type:"chromex.dispatch",portName:t.portName,payload:e},null,(function(e){if(e){var o=e.error,i=e.value;if(o){var a=Error("".concat(R).concat(o));n(j(a,o))}else r(i&&i.payload)}else{var c=t.browserAPI.runtime.lastError,u=Error("".concat(R).concat(c));n(j(u,c))}}))}))}},{key:"initializeStore",value:function(e){e&&"chromex.fetch_state"===e.type&&(this.replaceState(e.payload),this.readyResolved||(this.readyResolved=!0,this.readyResolve()))}}])&&r(n.prototype,o),i&&r(n,i),e}(),e.alias=function(e){return function(){return function(t){return function(r){var n=e[r.type];return t(n?n(r):r)}}}},e.applyMiddleware=function(e){for(var t=arguments.length,r=Array(t>1?t-1:0),n=1;t>n;n++)r[n-1]=arguments[n];var o=function(){throw Error("Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch.")},a={getState:e.getState.bind(e),dispatch:function(){return o.apply(void 0,arguments)}};return r=(r||[]).map((function(e){return e(a)})),o=_.apply(void 0,i(r))(e.dispatch),e.dispatch=o,e},e.createWrapStore=function(){var e=N(),t=L(),r=L();return e.runtime.onMessage.addListener(t.listener),e.runtime.onMessage.addListener(r.listener),function(n){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I,i=o.portName,a=void 0===i?I.portName:i,c=o.dispatchResponder,u=void 0===c?I.dispatchResponder:c,s=o.serializer,l=void 0===s?I.serializer:s,f=o.deserializer,p=void 0===f?I.deserializer:f,h=o.diffStrategy,d=void 0===h?I.diffStrategy:h;if(!a)throw Error("portName is required in options");if("function"!=typeof l)throw Error("serializer must be a function");if("function"!=typeof p)throw Error("deserializer must be a function");if("function"!=typeof d)throw Error("diffStrategy must be one of the included diffing strategies or a custom diff function");var y=function(e,t,r){if("chromex.dispatch"===e.type&&e.portName===a){var o=Object.assign({},e.payload,{_sender:t}),i=null;try{i=n.dispatch(o)}catch(e){i=Promise.reject(e.message),console.error(e)}return u(i,r),!0}},v=x(l)((function(){for(var t,r=arguments.length,n=Array(r),o=0;r>o;o++)n[o]=arguments[o];var i=function(){};return(t=e.runtime).sendMessage.apply(t,n.concat([i])),e.tabs.query({},(function(t){var r=!0,o=!1,a=void 0;try{for(var c,u=t[Symbol.iterator]();!(r=(c=u.next()).done);r=!0){var s;(s=e.tabs).sendMessage.apply(s,[c.value.id].concat(n,[i]))}}catch(e){o=!0,a=e}finally{try{r||null==u.return||u.return()}finally{if(o)throw a}}}))})),g=n.getState(),m=function(){var e=n.getState(),t=d(g,e);t.length&&(g=e,v({type:"chromex.patch_state",payload:t,portName:a}))};n.subscribe(m),v({type:"chromex.state",payload:g,portName:a});var b=k(p),w=function(e){return"chromex.dispatch"===e.type&&e.portName===a};t.setListener((function(e,t,r){var o=n.getState();"chromex.fetch_state"===e.type&&e.portName===a&&r({type:"chromex.fetch_state",payload:o})})),b(r.setListener)(y,w)}},Object.defineProperty(e,"__esModule",{value:!0})})); |
@@ -1,2 +0,2 @@ | ||
import * as redux from 'redux'; | ||
import * as redux from "redux"; | ||
@@ -9,11 +9,10 @@ export type DiffStrategy = (oldObj: any, newObj: any) => any; | ||
* Creates a new Proxy store | ||
* @param options An object of form {portName, state, extensionId}, where `portName` is a required string and defines the name of the port for state transition changes, `state` is the initial state of this store (default `{}`) `extensionId` is the extension id as defined by chrome when extension is loaded (default `''`) | ||
* @param options An object of form {portName, state}, where `portName` is a required string and defines the name of the port for state transition changes and `state` is the initial state of this store (default `{}`) | ||
*/ | ||
constructor(options?: { | ||
portName?: string, | ||
state?: any, | ||
extensionId?: string, | ||
serializer?: Function, | ||
deserializer?: Function, | ||
patchStrategy?: PatchStrategy | ||
portName?: string; | ||
state?: any; | ||
serializer?: Function; | ||
deserializer?: Function; | ||
patchStrategy?: PatchStrategy; | ||
}); | ||
@@ -24,3 +23,3 @@ | ||
* @return promise A promise that resolves when the store has established a connection with the background page. | ||
*/ | ||
*/ | ||
ready(): Promise<void>; | ||
@@ -32,10 +31,10 @@ | ||
* @return promise A promise that resolves when the store has established a connection with the background page. | ||
*/ | ||
*/ | ||
ready<S>(cb: () => S): Promise<S>; | ||
/** | ||
* Subscribes a listener function for all state changes | ||
* @param listener A listener function to be called when store state changes | ||
* @return An unsubscribe function which can be called to remove the listener from state updates | ||
*/ | ||
* Subscribes a listener function for all state changes | ||
* @param listener A listener function to be called when store state changes | ||
* @return An unsubscribe function which can be called to remove the listener from state updates | ||
*/ | ||
subscribe(listener: () => void): () => void; | ||
@@ -55,3 +54,2 @@ | ||
/** | ||
@@ -72,3 +70,3 @@ * Stub function to stay consistent with Redux Store API. No-op. | ||
* @param data The action data to dispatch | ||
* | ||
* | ||
* Note: Although the return type is specified as the action, react-chrome-redux will | ||
@@ -86,18 +84,26 @@ * wrap the result in a responsePromise that will resolve/reject based on the | ||
*/ | ||
[Symbol.observable](): Observable<S> | ||
[Symbol.observable](): Observable<S>; | ||
} | ||
export function wrapStore<S, A extends redux.Action = redux.AnyAction>( | ||
type WrapStore<S, A extends redux.Action = redux.AnyAction> = ( | ||
store: redux.Store<S, A>, | ||
configuration?: { | ||
portName?: string, | ||
dispatchResponder?(dispatchResult: any, send: (response: any) => void): void, | ||
serializer?: Function, | ||
deserializer?: Function, | ||
diffStrategy?: DiffStrategy | ||
}, | ||
): void; | ||
portName?: string; | ||
dispatchResponder?( | ||
dispatchResult: any, | ||
send: (response: any) => void | ||
): void; | ||
serializer?: Function; | ||
deserializer?: Function; | ||
diffStrategy?: DiffStrategy; | ||
} | ||
) => void; | ||
export function createWrapStore< | ||
S, | ||
A extends redux.Action = redux.AnyAction | ||
>(): WrapStore<S, A>; | ||
export function alias(aliases: { | ||
[key: string]: (action: any) => any | ||
[key: string]: (action: any) => any; | ||
}): redux.Middleware; | ||
@@ -114,3 +120,3 @@ | ||
export interface Unsubscribe { | ||
(): void | ||
(): void; | ||
} | ||
@@ -132,5 +138,5 @@ | ||
*/ | ||
subscribe: (observer: Observer<T>) => { unsubscribe: Unsubscribe } | ||
[Symbol.observable](): Observable<T> | ||
} | ||
subscribe: (observer: Observer<T>) => { unsubscribe: Unsubscribe }; | ||
[Symbol.observable](): Observable<T>; | ||
}; | ||
@@ -142,3 +148,3 @@ /** | ||
export type Observer<T> = { | ||
next?(value: T): void | ||
} | ||
next?(value: T): void; | ||
}; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -6,9 +6,13 @@ "use strict"; | ||
}); | ||
exports.DEFAULT_PORT_NAME = exports.PATCH_STATE_TYPE = exports.STATE_TYPE = exports.DISPATCH_TYPE = void 0; | ||
exports.DEFAULT_PORT_NAME = exports.PATCH_STATE_TYPE = exports.STATE_TYPE = exports.FETCH_STATE_TYPE = exports.DISPATCH_TYPE = void 0; | ||
// Message type used for dispatch events | ||
// from the Proxy Stores to background | ||
var DISPATCH_TYPE = 'chromex.dispatch'; // Message type for state update events from | ||
var DISPATCH_TYPE = 'chromex.dispatch'; // Message type for fetching current state from | ||
// background to Proxy Stores | ||
exports.DISPATCH_TYPE = DISPATCH_TYPE; | ||
var FETCH_STATE_TYPE = 'chromex.fetch_state'; // Message type for state update events from | ||
// background to Proxy Stores | ||
exports.FETCH_STATE_TYPE = FETCH_STATE_TYPE; | ||
var STATE_TYPE = 'chromex.state'; // Message type for state patch events from | ||
@@ -15,0 +19,0 @@ // background to Proxy Stores |
@@ -18,3 +18,3 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "wrapStore", { | ||
Object.defineProperty(exports, "createWrapStore", { | ||
enumerable: true, | ||
@@ -21,0 +21,0 @@ get: function get() { |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -30,3 +30,2 @@ "use strict"; | ||
state: {}, | ||
extensionId: null, | ||
serializer: _serialization.noop, | ||
@@ -42,3 +41,3 @@ deserializer: _serialization.noop, | ||
* Creates a new Proxy store | ||
* @param {object} options An object of form {portName, state, extensionId, serializer, deserializer, diffStrategy}, where `portName` is a required string and defines the name of the port for state transition changes, `state` is the initial state of this store (default `{}`) `extensionId` is the extension id as defined by browserAPI when extension is loaded (default `''`), `serializer` is a function to serialize outgoing message payloads (default is passthrough), `deserializer` is a function to deserialize incoming message payloads (default is passthrough), and patchStrategy is one of the included patching strategies (default is shallow diff) or a custom patching function. | ||
* @param {object} options An object of form {portName, state, serializer, deserializer, diffStrategy}, where `portName` is a required string and defines the name of the port for state transition changes, `state` is the initial state of this store (default `{}`) `serializer` is a function to serialize outgoing message payloads (default is passthrough), `deserializer` is a function to deserialize incoming message payloads (default is passthrough), and patchStrategy is one of the included patching strategies (default is shallow diff) or a custom patching function. | ||
*/ | ||
@@ -53,4 +52,2 @@ function Store() { | ||
state = _ref$state === void 0 ? defaultOpts.state : _ref$state, | ||
_ref$extensionId = _ref.extensionId, | ||
extensionId = _ref$extensionId === void 0 ? defaultOpts.extensionId : _ref$extensionId, | ||
_ref$serializer = _ref.serializer, | ||
@@ -87,23 +84,19 @@ serializer = _ref$serializer === void 0 ? defaultOpts.serializer : _ref$serializer, | ||
this.browserAPI = (0, _util.getBrowserAPI)(); | ||
this.extensionId = extensionId; // keep the extensionId as an instance variable | ||
this.initializeStore = this.initializeStore.bind(this); // We request the latest available state data to initialise our store | ||
this.port = this.browserAPI.runtime.connect(this.extensionId, { | ||
name: portName | ||
}); | ||
this.safetyHandler = this.safetyHandler.bind(this); | ||
if (this.browserAPI.runtime.onMessage) { | ||
this.safetyMessage = this.browserAPI.runtime.onMessage.addListener(this.safetyHandler); | ||
} | ||
this.browserAPI.runtime.sendMessage({ | ||
type: _constants.FETCH_STATE_TYPE, | ||
portName: portName | ||
}, undefined, this.initializeStore); | ||
this.deserializer = deserializer; | ||
this.serializedPortListener = (0, _serialization.withDeserializer)(deserializer)(function () { | ||
var _this$port$onMessage; | ||
var _this$browserAPI$runt; | ||
return (_this$port$onMessage = _this.port.onMessage).addListener.apply(_this$port$onMessage, arguments); | ||
return (_this$browserAPI$runt = _this.browserAPI.runtime.onMessage).addListener.apply(_this$browserAPI$runt, arguments); | ||
}); | ||
this.serializedMessageSender = (0, _serialization.withSerializer)(serializer)(function () { | ||
var _this$browserAPI$runt; | ||
var _this$browserAPI$runt2; | ||
return (_this$browserAPI$runt = _this.browserAPI.runtime).sendMessage.apply(_this$browserAPI$runt, arguments); | ||
}, 1); | ||
return (_this$browserAPI$runt2 = _this.browserAPI.runtime).sendMessage.apply(_this$browserAPI$runt2, arguments); | ||
}, 0); | ||
this.listeners = []; | ||
@@ -114,21 +107,23 @@ this.state = state; | ||
this.serializedPortListener(function (message) { | ||
switch (message.type) { | ||
case _constants.STATE_TYPE: | ||
_this.replaceState(message.payload); | ||
if (message.portName === _this.portName) { | ||
switch (message.type) { | ||
case _constants.STATE_TYPE: | ||
_this.replaceState(message.payload); | ||
if (!_this.readyResolved) { | ||
_this.readyResolved = true; | ||
if (!_this.readyResolved) { | ||
_this.readyResolved = true; | ||
_this.readyResolve(); | ||
} | ||
_this.readyResolve(); | ||
} | ||
break; | ||
break; | ||
case _constants.PATCH_STATE_TYPE: | ||
_this.patchState(message.payload); | ||
case _constants.PATCH_STATE_TYPE: | ||
_this.patchState(message.payload); | ||
break; | ||
break; | ||
default: // do nothing | ||
default: // do nothing | ||
} | ||
} | ||
@@ -231,3 +226,3 @@ }); | ||
return new Promise(function (resolve, reject) { | ||
_this3.serializedMessageSender(_this3.extensionId, { | ||
_this3.serializedMessageSender({ | ||
type: _constants.DISPATCH_TYPE, | ||
@@ -258,7 +253,6 @@ portName: _this3.portName, | ||
}, { | ||
key: "safetyHandler", | ||
value: function safetyHandler(message) { | ||
if (message.action === 'storeReady' && message.portName === this.portName) { | ||
// Remove Saftey Listener | ||
this.browserAPI.runtime.onMessage.removeListener(this.safetyHandler); // Resolve if readyPromise has not been resolved. | ||
key: "initializeStore", | ||
value: function initializeStore(message) { | ||
if (message && message.type === _constants.FETCH_STATE_TYPE) { | ||
this.replaceState(message.payload); // Resolve if readyPromise has not been resolved. | ||
@@ -265,0 +259,0 @@ if (!this.readyResolved) { |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -16,2 +16,4 @@ "use strict"; | ||
var _listener = require("../listener"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -32,3 +34,3 @@ | ||
}).catch(function (err) { | ||
console.error('error dispatching result:', err); | ||
console.error("error dispatching result:", err); | ||
send({ | ||
@@ -49,83 +51,148 @@ error: err.message, | ||
/** | ||
* Wraps a Redux store so that proxy stores can connect to it. | ||
* @typedef {function} WrapStore | ||
* @param {Object} store A Redux store | ||
* @param {Object} options An object of form {portName, dispatchResponder, serializer, deserializer}, where `portName` is a required string and defines the name of the port for state transition changes, `dispatchResponder` is a function that takes the result of a store dispatch and optionally implements custom logic for responding to the original dispatch message,`serializer` is a function to serialize outgoing message payloads (default is passthrough), `deserializer` is a function to deserialize incoming message payloads (default is passthrough), and diffStrategy is one of the included diffing strategies (default is shallow diff) or a custom diffing function. | ||
* @param {Object} options | ||
* @param {string} options.portName The name of the port for state transition | ||
* changes. | ||
* @param {function} options.dispatchResponder A function that takes the result | ||
* of a store dispatch and optionally implements custom logic for responding to | ||
* the original dispatch message. | ||
* @param {function} options.serializer A function to serialize outgoing message | ||
* payloads (default is passthrough). | ||
* @param {function} options.deserializer A function to deserialize incoming | ||
* message payloads (default is passthrough). | ||
* @param {function} options.diffStrategy A function to diff the previous state | ||
* and the new state (default is shallow diff). | ||
*/ | ||
var _default = function _default(store) { | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts, | ||
_ref$portName = _ref.portName, | ||
portName = _ref$portName === void 0 ? defaultOpts.portName : _ref$portName, | ||
_ref$dispatchResponde = _ref.dispatchResponder, | ||
dispatchResponder = _ref$dispatchResponde === void 0 ? defaultOpts.dispatchResponder : _ref$dispatchResponde, | ||
_ref$serializer = _ref.serializer, | ||
serializer = _ref$serializer === void 0 ? defaultOpts.serializer : _ref$serializer, | ||
_ref$deserializer = _ref.deserializer, | ||
deserializer = _ref$deserializer === void 0 ? defaultOpts.deserializer : _ref$deserializer, | ||
_ref$diffStrategy = _ref.diffStrategy, | ||
diffStrategy = _ref$diffStrategy === void 0 ? defaultOpts.diffStrategy : _ref$diffStrategy; | ||
/** | ||
* Wraps a Redux store so that proxy stores can connect to it. This function | ||
* must be called synchronously when the extension loads to avoid dropping | ||
* messages that woke the service worker. | ||
* @return {WrapStore} The wrapStore function that accepts a Redux store and | ||
* options. See {@link WrapStore}. | ||
*/ | ||
if (!portName) { | ||
throw new Error('portName is required in options'); | ||
} | ||
var _default = function _default() { | ||
var browserAPI = (0, _util.getBrowserAPI)(); // Setup message listeners synchronously to avoid dropping messages if the | ||
// extension is woken by a message. | ||
if (typeof serializer !== 'function') { | ||
throw new Error('serializer must be a function'); | ||
} | ||
var stateProviderListener = (0, _listener.createDeferredListener)(); | ||
var actionListener = (0, _listener.createDeferredListener)(); | ||
browserAPI.runtime.onMessage.addListener(stateProviderListener.listener); | ||
browserAPI.runtime.onMessage.addListener(actionListener.listener); | ||
return function (store) { | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts, | ||
_ref$portName = _ref.portName, | ||
portName = _ref$portName === void 0 ? defaultOpts.portName : _ref$portName, | ||
_ref$dispatchResponde = _ref.dispatchResponder, | ||
dispatchResponder = _ref$dispatchResponde === void 0 ? defaultOpts.dispatchResponder : _ref$dispatchResponde, | ||
_ref$serializer = _ref.serializer, | ||
serializer = _ref$serializer === void 0 ? defaultOpts.serializer : _ref$serializer, | ||
_ref$deserializer = _ref.deserializer, | ||
deserializer = _ref$deserializer === void 0 ? defaultOpts.deserializer : _ref$deserializer, | ||
_ref$diffStrategy = _ref.diffStrategy, | ||
diffStrategy = _ref$diffStrategy === void 0 ? defaultOpts.diffStrategy : _ref$diffStrategy; | ||
if (typeof deserializer !== 'function') { | ||
throw new Error('deserializer must be a function'); | ||
} | ||
if (!portName) { | ||
throw new Error("portName is required in options"); | ||
} | ||
if (typeof diffStrategy !== 'function') { | ||
throw new Error('diffStrategy must be one of the included diffing strategies or a custom diff function'); | ||
} | ||
if (typeof serializer !== "function") { | ||
throw new Error("serializer must be a function"); | ||
} | ||
var browserAPI = (0, _util.getBrowserAPI)(); | ||
/** | ||
* Respond to dispatches from UI components | ||
*/ | ||
if (typeof deserializer !== "function") { | ||
throw new Error("deserializer must be a function"); | ||
} | ||
var dispatchResponse = function dispatchResponse(request, sender, sendResponse) { | ||
if (request.type === _constants.DISPATCH_TYPE && request.portName === portName) { | ||
var action = Object.assign({}, request.payload, { | ||
_sender: sender | ||
}); | ||
var dispatchResult = null; | ||
if (typeof diffStrategy !== "function") { | ||
throw new Error("diffStrategy must be one of the included diffing strategies or a custom diff function"); | ||
} | ||
/** | ||
* Respond to dispatches from UI components | ||
*/ | ||
try { | ||
dispatchResult = store.dispatch(action); | ||
} catch (e) { | ||
dispatchResult = Promise.reject(e.message); | ||
console.error(e); | ||
var dispatchResponse = function dispatchResponse(request, sender, sendResponse) { | ||
if (request.type === _constants.DISPATCH_TYPE && request.portName === portName) { | ||
var action = Object.assign({}, request.payload, { | ||
_sender: sender | ||
}); | ||
var dispatchResult = null; | ||
try { | ||
dispatchResult = store.dispatch(action); | ||
} catch (e) { | ||
dispatchResult = Promise.reject(e.message); | ||
console.error(e); | ||
} | ||
dispatchResponder(dispatchResult, sendResponse); | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Setup for state updates | ||
*/ | ||
dispatchResponder(dispatchResult, sendResponse); | ||
return true; | ||
} | ||
}; | ||
/** | ||
* Setup for state updates | ||
*/ | ||
var serializedMessagePoster = (0, _serialization.withSerializer)(serializer)(function () { | ||
var _browserAPI$runtime; | ||
var connectState = function connectState(port) { | ||
if (port.name !== portName) { | ||
return; | ||
} | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var serializedMessagePoster = (0, _serialization.withSerializer)(serializer)(function () { | ||
return port.postMessage.apply(port, arguments); | ||
var onErrorCallback = function onErrorCallback() { | ||
if (browserAPI.runtime.lastError) {// do nothing - errors can be present | ||
// if no content script exists on receiver | ||
} | ||
}; | ||
(_browserAPI$runtime = browserAPI.runtime).sendMessage.apply(_browserAPI$runtime, args.concat([onErrorCallback])); // We will broadcast state changes to all tabs to sync state across content scripts | ||
return browserAPI.tabs.query({}, function (tabs) { | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = tabs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _browserAPI$tabs; | ||
var tab = _step.value; | ||
(_browserAPI$tabs = browserAPI.tabs).sendMessage.apply(_browserAPI$tabs, [tab.id].concat(args, [onErrorCallback])); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
var prevState = store.getState(); | ||
var currentState = store.getState(); | ||
var patchState = function patchState() { | ||
var state = store.getState(); | ||
var diff = diffStrategy(prevState, state); | ||
var newState = store.getState(); | ||
var diff = diffStrategy(currentState, newState); | ||
if (diff.length) { | ||
prevState = state; | ||
currentState = newState; | ||
serializedMessagePoster({ | ||
type: _constants.PATCH_STATE_TYPE, | ||
payload: diff | ||
payload: diff, | ||
portName: portName // Notifying what extension is broadcasting the state changes | ||
}); | ||
@@ -136,96 +203,38 @@ } | ||
var unsubscribe = store.subscribe(patchState); // when the port disconnects, unsubscribe the sendState listener | ||
store.subscribe(patchState); // Send store's initial state through port | ||
port.onDisconnect.addListener(unsubscribe); // Send store's initial state through port | ||
serializedMessagePoster({ | ||
type: _constants.STATE_TYPE, | ||
payload: prevState | ||
payload: currentState, | ||
portName: portName // Notifying what extension is broadcasting the state changes | ||
}); | ||
}; | ||
var withPayloadDeserializer = (0, _serialization.withDeserializer)(deserializer); | ||
var withPayloadDeserializer = (0, _serialization.withDeserializer)(deserializer); | ||
var shouldDeserialize = function shouldDeserialize(request) { | ||
return request.type === _constants.DISPATCH_TYPE && request.portName === portName; | ||
}; | ||
/** | ||
* State provider for content-script initialization | ||
*/ | ||
var shouldDeserialize = function shouldDeserialize(request) { | ||
return request.type === _constants.DISPATCH_TYPE && request.portName === portName; | ||
}; | ||
/** | ||
* Setup action handler | ||
*/ | ||
stateProviderListener.setListener(function (request, sender, sendResponse) { | ||
var state = store.getState(); | ||
withPayloadDeserializer(function () { | ||
var _browserAPI$runtime$o; | ||
return (_browserAPI$runtime$o = browserAPI.runtime.onMessage).addListener.apply(_browserAPI$runtime$o, arguments); | ||
})(dispatchResponse, shouldDeserialize); | ||
/** | ||
* Setup external action handler | ||
*/ | ||
if (browserAPI.runtime.onMessageExternal) { | ||
withPayloadDeserializer(function () { | ||
var _browserAPI$runtime$o2; | ||
return (_browserAPI$runtime$o2 = browserAPI.runtime.onMessageExternal).addListener.apply(_browserAPI$runtime$o2, arguments); | ||
})(dispatchResponse, shouldDeserialize); | ||
} else { | ||
console.warn('runtime.onMessageExternal is not supported'); | ||
} | ||
/** | ||
* Setup extended connection | ||
*/ | ||
browserAPI.runtime.onConnect.addListener(connectState); | ||
/** | ||
* Setup extended external connection | ||
*/ | ||
if (browserAPI.runtime.onConnectExternal) { | ||
browserAPI.runtime.onConnectExternal.addListener(connectState); | ||
} else { | ||
console.warn('runtime.onConnectExternal is not supported'); | ||
} | ||
/** | ||
* Safety message to tabs for content scripts | ||
*/ | ||
browserAPI.tabs.query({}, function (tabs) { | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = tabs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var tab = _step.value; | ||
browserAPI.tabs.sendMessage(tab.id, { | ||
action: 'storeReady', | ||
portName: portName | ||
}, function () { | ||
if (chrome.runtime.lastError) {// do nothing - errors can be present | ||
// if no content script exists on reciever | ||
} | ||
if (request.type === _constants.FETCH_STATE_TYPE && request.portName === portName) { | ||
sendResponse({ | ||
type: _constants.FETCH_STATE_TYPE, | ||
payload: state | ||
}); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
}); // For non-tab based | ||
// TODO: Find use case for this. Ommiting until then. | ||
// browserAPI.runtime.sendMessage(null, {action: 'storeReady'}); | ||
}); | ||
/** | ||
* Setup action handler | ||
*/ | ||
withPayloadDeserializer(actionListener.setListener)(dispatchResponse, shouldDeserialize); | ||
}; | ||
}; | ||
exports.default = _default; |
{ | ||
"name": "webext-redux", | ||
"version": "2.1.9", | ||
"version": "3.0.0-mv3.0", | ||
"description": "A set of utilities for building Redux applications in Web Extensions.", | ||
@@ -9,6 +9,7 @@ "main": "lib/index.js", | ||
"umd-build": "rollup -c", | ||
"build": "./node_modules/.bin/babel src --out-dir lib && npm run umd-build", | ||
"lint-src": "./node_modules/.bin/eslint src/**/*.js", | ||
"lint-test": "./node_modules/.bin/eslint test/**/*.js", | ||
"lint": "npm run lint-src && npm run lint-test", | ||
"prepublishOnly": "./node_modules/.bin/babel src --out-dir lib && npm run umd-build", | ||
"prepublishOnly": "npm run build", | ||
"pretest": "./node_modules/.bin/babel src --out-dir lib", | ||
@@ -15,0 +16,0 @@ "test-run": "./node_modules/.bin/mocha --require @babel/register --recursive", |
# WebExt Redux | ||
A set of utilities for building Redux applications in web extensions. This package was originally named `react-chrome-redux`. | ||
[![Build Status](https://travis-ci.org/tshaddix/webext-redux.svg?branch=master)](https://travis-ci.org/tshaddix/webext-redux) | ||
[![NPM Version][npm-image]][npm-url] | ||
@@ -6,0 +5,0 @@ [![NPM Downloads][downloads-image]][downloads-url] |
@@ -0,0 +0,0 @@ import nodeResolve from 'rollup-plugin-node-resolve'; |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
140145
30
2895
1
469
1