redux-saga
Advanced tools
Comparing version 1.0.0-beta.3 to 1.0.0-rc.0
@@ -8,8 +8,7 @@ 'use strict'; | ||
var is = require('@redux-saga/is'); | ||
var __chunk_1 = require('./chunk-5caa0f1a.js'); | ||
var __chunk_1 = require('./chunk-0e1a6d35.js'); | ||
var symbols = require('@redux-saga/symbols'); | ||
var __chunk_2 = require('./chunk-062c0282.js'); | ||
var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); | ||
var deferred = _interopDefault(require('@redux-saga/deferred')); | ||
var redux = require('redux'); | ||
var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); | ||
var _objectWithoutPropertiesLoose = _interopDefault(require('@babel/runtime/helpers/objectWithoutPropertiesLoose')); | ||
@@ -56,2 +55,14 @@ require('@redux-saga/delay-p'); | ||
/** | ||
* Puts the scheduler in a `suspended` state and executes a task immediately. | ||
*/ | ||
function immediately(task) { | ||
try { | ||
suspend(); | ||
return task(); | ||
} finally { | ||
flush(); | ||
} | ||
} | ||
/** | ||
Puts the scheduler in a `suspended` state. Scheduled tasks will be queued until the | ||
@@ -68,2 +79,3 @@ scheduler is released. | ||
function release() { | ||
@@ -133,3 +145,3 @@ semaphore--; | ||
if (buffer === void 0) { | ||
buffer = __chunk_2.expanding(); | ||
buffer = __chunk_1.expanding(); | ||
} | ||
@@ -191,3 +203,3 @@ | ||
function flush$$1(cb) { | ||
function flush(cb) { | ||
{ | ||
@@ -228,3 +240,3 @@ checkForbiddenStates(); | ||
put: put, | ||
flush: flush$$1, | ||
flush: flush, | ||
close: close | ||
@@ -235,3 +247,3 @@ }; | ||
if (buffer === void 0) { | ||
buffer = __chunk_2.none(); | ||
buffer = __chunk_1.none(); | ||
} | ||
@@ -382,127 +394,416 @@ | ||
function formatLocation(fileName, lineNumber) { | ||
return fileName + "?" + lineNumber; | ||
var RUNNING = 0; | ||
var CANCELLED = 1; | ||
var ABORTED = 2; | ||
var DONE = 3; | ||
function resolvePromise(promise, cb) { | ||
var cancelPromise = promise[symbols.CANCEL]; | ||
if (is.func(cancelPromise)) { | ||
cb.cancel = cancelPromise; | ||
} | ||
promise.then(cb, function (error) { | ||
cb(error, true); | ||
}); | ||
} | ||
function getLocation(instrumented) { | ||
return instrumented[symbols.SAGA_LOCATION]; | ||
var current = 0; | ||
var nextEffectId = (function () { | ||
return ++current; | ||
}); | ||
var _effectRunnerMap; | ||
function getIteratorMetaInfo(iterator, fn) { | ||
if (iterator.isSagaIterator) { | ||
return { | ||
name: iterator.meta.name | ||
}; | ||
} | ||
return __chunk_1.getMetaInfo(fn); | ||
} | ||
function effectLocationAsString(effect) { | ||
var location = getLocation(effect); | ||
function createTaskIterator(_ref) { | ||
var context = _ref.context, | ||
fn = _ref.fn, | ||
args = _ref.args; | ||
if (location) { | ||
var code = location.code, | ||
fileName = location.fileName, | ||
lineNumber = location.lineNumber; | ||
var source = code + " " + formatLocation(fileName, lineNumber); | ||
return source; | ||
// catch synchronous failures; see #152 and #441 | ||
try { | ||
var result = fn.apply(context, args); // i.e. a generator function returns an iterator | ||
if (is.iterator(result)) { | ||
return result; | ||
} | ||
var next = function next(value) { | ||
if (value === void 0) { | ||
value = result; | ||
} | ||
return { | ||
value: value, | ||
done: !is.promise(value) | ||
}; | ||
}; | ||
return __chunk_1.makeIterator(next); | ||
} catch (err) { | ||
// do not bubble up synchronous failures for detached forks | ||
// instead create a failed task. See #152 and #441 | ||
return __chunk_1.makeIterator(function () { | ||
throw err; | ||
}); | ||
} | ||
} | ||
return ''; | ||
function runPutEffect(env, _ref2, cb) { | ||
var channel$$1 = _ref2.channel, | ||
action = _ref2.action, | ||
resolve = _ref2.resolve; | ||
/** | ||
Schedule the put in case another saga is holding a lock. | ||
The put will be executed atomically. ie nested puts will execute after | ||
this put has terminated. | ||
**/ | ||
asap(function () { | ||
var result; | ||
try { | ||
result = (channel$$1 ? channel$$1.put : env.dispatch)(action); | ||
} catch (error) { | ||
cb(error, true); | ||
return; | ||
} | ||
if (resolve && is.promise(result)) { | ||
resolvePromise(result, cb); | ||
} else { | ||
cb(result); | ||
} | ||
}); // Put effects are non cancellables | ||
} | ||
function sagaLocationAsString(sagaMeta) { | ||
var name = sagaMeta.name, | ||
location = sagaMeta.location; | ||
function runTakeEffect(env, _ref3, cb) { | ||
var _ref3$channel = _ref3.channel, | ||
channel$$1 = _ref3$channel === void 0 ? env.channel : _ref3$channel, | ||
pattern = _ref3.pattern, | ||
maybe = _ref3.maybe; | ||
if (location) { | ||
return name + " " + formatLocation(location.fileName, location.lineNumber); | ||
var takeCb = function takeCb(input) { | ||
if (input instanceof Error) { | ||
cb(input, true); | ||
return; | ||
} | ||
if (isEnd(input) && !maybe) { | ||
cb(symbols.TERMINATE); | ||
return; | ||
} | ||
cb(input); | ||
}; | ||
try { | ||
channel$$1.take(takeCb, is.notUndef(pattern) ? matcher(pattern) : null); | ||
} catch (err) { | ||
cb(err, true); | ||
return; | ||
} | ||
return name; | ||
cb.cancel = takeCb.cancel; | ||
} | ||
var flatMap = function flatMap(mapper, arr) { | ||
var _ref; | ||
function runCallEffect(env, _ref4, cb, _ref5) { | ||
var context = _ref4.context, | ||
fn = _ref4.fn, | ||
args = _ref4.args; | ||
var task = _ref5.task; | ||
return (_ref = []).concat.apply(_ref, arr.map(mapper)); | ||
}; | ||
// catch synchronous failures; see #152 | ||
try { | ||
var result = fn.apply(context, args); | ||
function cancelledTasksAsString(sagaStack) { | ||
var cancelledTasks = flatMap(function (i) { | ||
return i.cancelledTasks; | ||
}, sagaStack); | ||
if (is.promise(result)) { | ||
resolvePromise(result, cb); | ||
return; | ||
} | ||
if (!cancelledTasks.length) { | ||
return ''; | ||
if (is.iterator(result)) { | ||
// resolve iterator | ||
proc(env, result, task.context, current, __chunk_1.getMetaInfo(fn), | ||
/* isRoot */ | ||
false, cb); | ||
return; | ||
} | ||
cb(result); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
return ['Tasks cancelled due to error:'].concat(cancelledTasks).join('\n'); | ||
function runCPSEffect(env, _ref6, cb) { | ||
var context = _ref6.context, | ||
fn = _ref6.fn, | ||
args = _ref6.args; | ||
// CPS (ie node style functions) can define their own cancellation logic | ||
// by setting cancel field on the cb | ||
// catch synchronous failures; see #152 | ||
try { | ||
var cpsCb = function cpsCb(err, res) { | ||
if (is.undef(err)) { | ||
cb(res); | ||
} else { | ||
cb(err, true); | ||
} | ||
}; | ||
fn.apply(context, args.concat(cpsCb)); | ||
if (cpsCb.cancel) { | ||
cb.cancel = cpsCb.cancel; | ||
} | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
/** | ||
@param {saga, effect}[] sagaStack | ||
@returns {string} | ||
@example | ||
The above error occurred in task errorInPutSaga {pathToFile} | ||
when executing effect put({type: 'REDUCER_ACTION_ERROR_IN_PUT'}) {pathToFile} | ||
created by fetchSaga {pathToFile} | ||
created by rootSaga {pathToFile} | ||
*/ | ||
function runForkEffect(env, _ref7, cb, _ref8) { | ||
var context = _ref7.context, | ||
fn = _ref7.fn, | ||
args = _ref7.args, | ||
detached = _ref7.detached; | ||
var parent = _ref8.task; | ||
var taskIterator = createTaskIterator({ | ||
context: context, | ||
fn: fn, | ||
args: args | ||
}); | ||
var meta = getIteratorMetaInfo(taskIterator, fn); | ||
immediately(function () { | ||
var child = proc(env, taskIterator, parent.context, current, meta, detached, __chunk_1.noop); | ||
if (detached) { | ||
cb(child); | ||
} else { | ||
if (child.isRunning()) { | ||
parent.queue.addTask(child); | ||
cb(child); | ||
} else if (child.isAborted()) { | ||
parent.queue.abort(child.error()); | ||
} else { | ||
cb(child); | ||
} | ||
} | ||
}); // Fork effects are non cancellables | ||
} | ||
function sagaStackToString(sagaStack) { | ||
var firstSaga = sagaStack[0], | ||
otherSagas = sagaStack.slice(1); | ||
var crashedEffectLocation = firstSaga.effect ? effectLocationAsString(firstSaga.effect) : null; | ||
var errorMessage = "The above error occurred in task " + sagaLocationAsString(firstSaga.meta) + (crashedEffectLocation ? " \n when executing effect " + crashedEffectLocation : ''); | ||
return [errorMessage].concat(otherSagas.map(function (s) { | ||
return " created by " + sagaLocationAsString(s.meta); | ||
}), [cancelledTasksAsString(sagaStack)]).join('\n'); | ||
function runJoinEffect(env, taskOrTasks, cb, _ref9) { | ||
var task = _ref9.task; | ||
var joinSingleTask = function joinSingleTask(taskToJoin, cb) { | ||
if (taskToJoin.isRunning()) { | ||
var joiner = { | ||
task: task, | ||
cb: cb | ||
}; | ||
cb.cancel = function () { | ||
__chunk_1.remove(taskToJoin.joiners, joiner); | ||
}; | ||
taskToJoin.joiners.push(joiner); | ||
} else { | ||
if (taskToJoin.isAborted()) { | ||
cb(taskToJoin.error(), true); | ||
} else { | ||
cb(taskToJoin.result()); | ||
} | ||
} | ||
}; | ||
if (is.array(taskOrTasks)) { | ||
if (taskOrTasks.length === 0) { | ||
cb([]); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(taskOrTasks, cb); | ||
taskOrTasks.forEach(function (t, i) { | ||
joinSingleTask(t, childCallbacks[i]); | ||
}); | ||
} else { | ||
joinSingleTask(taskOrTasks, cb); | ||
} | ||
} | ||
function addSagaStack(errorObject, errorStack) { | ||
if (typeof errorObject === 'object') { | ||
if (typeof errorObject.sagaStack === 'undefined') { | ||
// property is used as a stack of descriptors for failed sagas | ||
// after formatting to string it will be re-written | ||
// to pass sagaStack as a string in user land | ||
Object.defineProperty(errorObject, 'sagaStack', { | ||
value: [], | ||
writable: true, | ||
enumerable: false | ||
function cancelSingleTask(taskToCancel) { | ||
if (taskToCancel.isRunning()) { | ||
taskToCancel.cancel(); | ||
} | ||
} | ||
function runCancelEffect(env, taskOrTasks, cb, _ref10) { | ||
var task = _ref10.task; | ||
if (taskOrTasks === symbols.SELF_CANCELLATION) { | ||
cancelSingleTask(task); | ||
} else if (is.array(taskOrTasks)) { | ||
taskOrTasks.forEach(cancelSingleTask); | ||
} else { | ||
cancelSingleTask(taskOrTasks); | ||
} | ||
cb(); // cancel effects are non cancellables | ||
} | ||
function runAllEffect(env, effects, cb, _ref11) { | ||
var digestEffect = _ref11.digestEffect; | ||
var effectId = current; | ||
var keys = Object.keys(effects); | ||
if (keys.length === 0) { | ||
cb(is.array(effects) ? [] : {}); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(effects, cb); | ||
keys.forEach(function (key) { | ||
digestEffect(effects[key], effectId, childCallbacks[key], key); | ||
}); | ||
} | ||
function runRaceEffect(env, effects, cb, _ref12) { | ||
var digestEffect = _ref12.digestEffect; | ||
var effectId = current; | ||
var keys = Object.keys(effects); | ||
var response = is.array(effects) ? __chunk_1.createEmptyArray(keys.length) : {}; | ||
var childCbs = {}; | ||
var completed = false; | ||
keys.forEach(function (key) { | ||
var chCbAtKey = function chCbAtKey(res, isErr) { | ||
if (completed) { | ||
return; | ||
} | ||
if (isErr || __chunk_1.shouldComplete(res)) { | ||
// Race Auto cancellation | ||
cb.cancel(); | ||
cb(res, isErr); | ||
} else { | ||
cb.cancel(); | ||
completed = true; | ||
response[key] = res; | ||
cb(response); | ||
} | ||
}; | ||
chCbAtKey.cancel = __chunk_1.noop; | ||
childCbs[key] = chCbAtKey; | ||
}); | ||
cb.cancel = function () { | ||
// prevents unnecessary cancellation | ||
if (!completed) { | ||
completed = true; | ||
keys.forEach(function (key) { | ||
return childCbs[key].cancel(); | ||
}); | ||
} | ||
}; | ||
errorObject.sagaStack.push(errorStack); | ||
keys.forEach(function (key) { | ||
if (completed) { | ||
return; | ||
} | ||
digestEffect(effects[key], effectId, childCbs[key], key); | ||
}); | ||
} | ||
function runSelectEffect(env, _ref13, cb) { | ||
var selector = _ref13.selector, | ||
args = _ref13.args; | ||
try { | ||
var state = selector.apply(void 0, [env.getState()].concat(args)); | ||
cb(state); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function getMetaInfo(fn) { | ||
return { | ||
name: fn.name || 'anonymous', | ||
location: getLocation(fn) | ||
function runChannelEffect(env, _ref14, cb) { | ||
var pattern = _ref14.pattern, | ||
buffer = _ref14.buffer; | ||
var chan = channel(buffer); | ||
var match = matcher(pattern); | ||
var taker = function taker(action) { | ||
if (!isEnd(action)) { | ||
env.channel.take(taker, match); | ||
} | ||
chan.put(action); | ||
}; | ||
var close = chan.close; | ||
chan.close = function () { | ||
taker.cancel(); | ||
close(); | ||
}; | ||
env.channel.take(taker, match); | ||
cb(chan); | ||
} | ||
function getIteratorMetaInfo(iterator, fn) { | ||
if (iterator.isSagaIterator) { | ||
return { | ||
name: iterator.meta.name | ||
}; | ||
} | ||
function runCancelledEffect(env, data, cb, _ref15) { | ||
var task = _ref15.task; | ||
cb(task.isCancelled()); | ||
} | ||
return getMetaInfo(fn); | ||
function runFlushEffect(env, channel$$1, cb) { | ||
channel$$1.flush(cb); | ||
} | ||
function runGetContextEffect(env, prop, cb, _ref16) { | ||
var task = _ref16.task; | ||
cb(task.context[prop]); | ||
} | ||
function runSetContextEffect(env, props, cb, _ref17) { | ||
var task = _ref17.task; | ||
__chunk_1.assignWithSymbols(task.context, props); | ||
cb(); | ||
} | ||
var effectRunnerMap = (_effectRunnerMap = {}, _effectRunnerMap[__chunk_1.TAKE] = runTakeEffect, _effectRunnerMap[__chunk_1.PUT] = runPutEffect, _effectRunnerMap[__chunk_1.ALL] = runAllEffect, _effectRunnerMap[__chunk_1.RACE] = runRaceEffect, _effectRunnerMap[__chunk_1.CALL] = runCallEffect, _effectRunnerMap[__chunk_1.CPS] = runCPSEffect, _effectRunnerMap[__chunk_1.FORK] = runForkEffect, _effectRunnerMap[__chunk_1.JOIN] = runJoinEffect, _effectRunnerMap[__chunk_1.CANCEL] = runCancelEffect, _effectRunnerMap[__chunk_1.SELECT] = runSelectEffect, _effectRunnerMap[__chunk_1.ACTION_CHANNEL] = runChannelEffect, _effectRunnerMap[__chunk_1.CANCELLED] = runCancelledEffect, _effectRunnerMap[__chunk_1.FLUSH] = runFlushEffect, _effectRunnerMap[__chunk_1.GET_CONTEXT] = runGetContextEffect, _effectRunnerMap[__chunk_1.SET_CONTEXT] = runSetContextEffect, _effectRunnerMap); | ||
/** | ||
Used to track a parent task and its forks | ||
In the new fork model, forked tasks are attached by default to their parent | ||
We model this using the concept of Parent task && main Task | ||
main task is the main flow of the current Generator, the parent tasks is the | ||
aggregation of the main tasks + all its forked tasks. | ||
Thus the whole model represents an execution tree with multiple branches (vs the | ||
linear execution tree in sequential (non parallel) programming) | ||
Used to track a parent task and its forks | ||
In the fork model, forked tasks are attached by default to their parent | ||
We model this using the concept of Parent task && main Task | ||
main task is the main flow of the current Generator, the parent tasks is the | ||
aggregation of the main tasks + all its forked tasks. | ||
Thus the whole model represents an execution tree with multiple branches (vs the | ||
linear execution tree in sequential (non parallel) programming) | ||
A parent tasks has the following semantics | ||
- It completes if all its forks either complete or all cancelled | ||
- If it's cancelled, all forks are cancelled as well | ||
- It aborts if any uncaught error bubbles up from forks | ||
- If it completes, the return value is the one returned by the main task | ||
**/ | ||
A parent tasks has the following semantics | ||
- It completes if all its forks either complete or all cancelled | ||
- If it's cancelled, all forks are cancelled as well | ||
- It aborts if any uncaught error bubbles up from forks | ||
- If it completes, the return value is the one returned by the main task | ||
**/ | ||
function forkQueue(mainTask, onAbort, cb) { | ||
var tasks = [], | ||
result, | ||
completed = false; | ||
function forkQueue(mainTask, onAbort, cont) { | ||
var tasks = []; | ||
var result; | ||
var completed = false; | ||
addTask(mainTask); | ||
@@ -514,12 +815,6 @@ | ||
var getTaskNames = function getTaskNames() { | ||
return tasks.map(function (t) { | ||
return t.meta.name; | ||
}); | ||
}; | ||
function abort(err) { | ||
onAbort(); | ||
cancelAll(); | ||
cb(err, true); | ||
cont(err, true); | ||
} | ||
@@ -547,7 +842,6 @@ | ||
completed = true; | ||
cb(result); | ||
cont(result); | ||
} | ||
} | ||
}; // task.cont.cancel = task.cancel | ||
}; | ||
} | ||
@@ -572,42 +866,197 @@ | ||
abort: abort, | ||
getTasks: getTasks, | ||
getTaskNames: getTaskNames | ||
getTasks: getTasks | ||
}; | ||
} | ||
function createTaskIterator(_ref) { | ||
var context = _ref.context, | ||
fn = _ref.fn, | ||
args = _ref.args; | ||
// there can be only a single saga error created at any given moment | ||
// catch synchronous failures; see #152 and #441 | ||
try { | ||
var result = fn.apply(context, args); // i.e. a generator function returns an iterator | ||
function formatLocation(fileName, lineNumber) { | ||
return fileName + "?" + lineNumber; | ||
} | ||
if (is.iterator(result)) { | ||
return result; | ||
function effectLocationAsString(effect) { | ||
var location = __chunk_1.getLocation(effect); | ||
if (location) { | ||
var code = location.code, | ||
fileName = location.fileName, | ||
lineNumber = location.lineNumber; | ||
var source = code + " " + formatLocation(fileName, lineNumber); | ||
return source; | ||
} | ||
return ''; | ||
} | ||
function sagaLocationAsString(sagaMeta) { | ||
var name = sagaMeta.name, | ||
location = sagaMeta.location; | ||
if (location) { | ||
return name + " " + formatLocation(location.fileName, location.lineNumber); | ||
} | ||
return name; | ||
} | ||
function cancelledTasksAsString(sagaStack) { | ||
var cancelledTasks = __chunk_1.flatMap(function (i) { | ||
return i.cancelledTasks; | ||
}, sagaStack); | ||
if (!cancelledTasks.length) { | ||
return ''; | ||
} | ||
return ['Tasks cancelled due to error:'].concat(cancelledTasks).join('\n'); | ||
} | ||
var crashedEffect = null; | ||
var sagaStack = []; | ||
var addSagaFrame = function addSagaFrame(frame) { | ||
frame.crashedEffect = crashedEffect; | ||
sagaStack.push(frame); | ||
}; | ||
var clear = function clear() { | ||
crashedEffect = null; | ||
sagaStack.length = 0; | ||
}; // this sets crashed effect for the soon-to-be-reported saga frame | ||
// this slightly streatches the singleton nature of this module into wrong direction | ||
// as it's even less obvious what's the data flow here, but it is what it is for now | ||
var setCrashedEffect = function setCrashedEffect(effect) { | ||
crashedEffect = effect; | ||
}; | ||
/** | ||
@returns {string} | ||
@example | ||
The above error occurred in task errorInPutSaga {pathToFile} | ||
when executing effect put({type: 'REDUCER_ACTION_ERROR_IN_PUT'}) {pathToFile} | ||
created by fetchSaga {pathToFile} | ||
created by rootSaga {pathToFile} | ||
*/ | ||
var toString = function toString() { | ||
var firstSaga = sagaStack[0], | ||
otherSagas = sagaStack.slice(1); | ||
var crashedEffectLocation = firstSaga.crashedEffect ? effectLocationAsString(firstSaga.crashedEffect) : null; | ||
var errorMessage = "The above error occurred in task " + sagaLocationAsString(firstSaga.meta) + (crashedEffectLocation ? " \n when executing effect " + crashedEffectLocation : ''); | ||
return [errorMessage].concat(otherSagas.map(function (s) { | ||
return " created by " + sagaLocationAsString(s.meta); | ||
}), [cancelledTasksAsString(sagaStack)]).join('\n'); | ||
}; | ||
function newTask(env, mainTask, parentContext, parentEffectId, meta, isRoot, cont) { | ||
var _task; | ||
var status = RUNNING; | ||
var taskResult; | ||
var taskError; | ||
var deferredEnd = null; | ||
var cancelledDueToErrorTasks = []; | ||
var context = Object.create(parentContext); | ||
var queue = forkQueue(mainTask, function onAbort() { | ||
cancelledDueToErrorTasks.push.apply(cancelledDueToErrorTasks, queue.getTasks().map(function (t) { | ||
return t.meta.name; | ||
})); | ||
}, end); | ||
/** | ||
This may be called by a parent generator to trigger/propagate cancellation | ||
cancel all pending tasks (including the main task), then end the current task. | ||
Cancellation propagates down to the whole execution tree held by this Parent task | ||
It's also propagated to all joiners of this task and their execution tree/joiners | ||
Cancellation is noop for terminated/Cancelled tasks tasks | ||
**/ | ||
function cancel() { | ||
if (status === RUNNING) { | ||
// Setting status to CANCELLED does not necessarily mean that the task/iterators are stopped | ||
// effects in the iterator's finally block will still be executed | ||
status = CANCELLED; | ||
queue.cancelAll(); // Ending with a TASK_CANCEL will propagate the Cancellation to all joiners | ||
end(symbols.TASK_CANCEL, false); | ||
} | ||
} | ||
var next = function next(value) { | ||
if (value === void 0) { | ||
value = result; | ||
function end(result, isErr) { | ||
if (!isErr) { | ||
// The status here may be RUNNING or CANCELLED | ||
// If the status is CANCELLED, then we do not need to change it here | ||
if (result === symbols.TASK_CANCEL) { | ||
status = CANCELLED; | ||
} else if (status !== CANCELLED) { | ||
status = DONE; | ||
} | ||
return { | ||
value: value, | ||
done: !is.promise(value) | ||
}; | ||
}; | ||
taskResult = result; | ||
deferredEnd && deferredEnd.resolve(result); | ||
} else { | ||
status = ABORTED; | ||
addSagaFrame({ | ||
meta: meta, | ||
cancelledTasks: cancelledDueToErrorTasks | ||
}); | ||
return __chunk_1.makeIterator(next); | ||
} catch (err) { | ||
// do not bubble up synchronous failures for detached forks | ||
// instead create a failed task. See #152 and #441 | ||
return __chunk_1.makeIterator(function () { | ||
throw err; | ||
if (task.isRoot) { | ||
var sagaStack = toString(); // we've dumped the saga stack to string and are passing it to user's code | ||
// we know that it won't be needed anymore and we need to clear it | ||
clear(); | ||
env.onError(result, { | ||
sagaStack: sagaStack | ||
}); | ||
} | ||
taskError = result; | ||
deferredEnd && deferredEnd.reject(result); | ||
} | ||
task.cont(result, isErr); | ||
task.joiners.forEach(function (joiner) { | ||
joiner.cb(result, isErr); | ||
}); | ||
task.joiners = null; | ||
} | ||
function setContext(props) { | ||
{ | ||
__chunk_1.check(props, is.object, __chunk_1.createSetContextWarning('task', props)); | ||
} | ||
__chunk_1.assignWithSymbols(context, props); | ||
} | ||
function toPromise() { | ||
if (deferredEnd) { | ||
return deferredEnd.promise; | ||
} | ||
deferredEnd = deferred(); | ||
if (status === ABORTED) { | ||
deferredEnd.reject(taskError); | ||
} else if (status !== RUNNING) { | ||
deferredEnd.resolve(taskResult); | ||
} | ||
return deferredEnd.promise; | ||
} | ||
var task = (_task = {}, _task[symbols.TASK] = true, _task.id = parentEffectId, _task.meta = meta, _task.isRoot = isRoot, _task.context = context, _task.joiners = [], _task.queue = queue, _task.cancel = cancel, _task.cont = cont, _task.end = end, _task.setContext = setContext, _task.toPromise = toPromise, _task.isRunning = function isRunning() { | ||
return status === RUNNING; | ||
}, _task.isCancelled = function isCancelled() { | ||
return status === CANCELLED || status === RUNNING && mainTask.status === CANCELLED; | ||
}, _task.isAborted = function isAborted() { | ||
return status === ABORTED; | ||
}, _task.result = function result() { | ||
return taskResult; | ||
}, _task.error = function error() { | ||
return taskError; | ||
}, _task); | ||
return task; | ||
} | ||
function proc(env, iterator, parentContext, parentEffectId, meta, cont) { | ||
function proc(env, iterator, parentContext, parentEffectId, meta, isRoot, cont) { | ||
if (iterator[__chunk_1.asyncIteratorSymbol]) { | ||
@@ -617,6 +1066,3 @@ throw new Error("redux-saga doesn't support async generators, please use only regular ones"); | ||
var taskContext = Object.create(parentContext); | ||
var finalRunEffect = env.finalizeRunEffect(runEffect); | ||
var crashedEffect = null; | ||
var cancelledDueToErrorTasks = []; | ||
/** | ||
@@ -629,24 +1075,27 @@ Tracks the current effect cancellation | ||
next.cancel = __chunk_1.noop; | ||
/** | ||
Creates a new task descriptor for this generator, We'll also create a main task | ||
to track the main flow (besides other forked tasks) | ||
**/ | ||
/** Creates a main task to track the main flow */ | ||
var task = newTask(parentEffectId, meta, cont); | ||
var mainTask = { | ||
meta: meta, | ||
cancel: cancelMain, | ||
_isRunning: true, | ||
_isCancelled: false | ||
status: RUNNING | ||
/** | ||
Creates a new task descriptor for this generator. | ||
A task is the aggregation of it's mainTask and all it's forked tasks. | ||
**/ | ||
}; | ||
var taskQueue = forkQueue(mainTask, function onAbort() { | ||
cancelledDueToErrorTasks.push.apply(cancelledDueToErrorTasks, taskQueue.getTaskNames()); | ||
}, end); | ||
/** | ||
cancellation of the main task. We'll simply resume the Generator with a Cancel | ||
**/ | ||
var task = newTask(env, mainTask, parentContext, parentEffectId, meta, isRoot, cont); | ||
var executingContext = { | ||
task: task, | ||
digestEffect: digestEffect | ||
/** | ||
cancellation of the main task. We'll simply resume the Generator with a TASK_CANCEL | ||
**/ | ||
}; | ||
function cancelMain() { | ||
if (mainTask._isRunning && !mainTask._isCancelled) { | ||
mainTask._isCancelled = true; | ||
if (mainTask.status === RUNNING) { | ||
mainTask.status = CANCELLED; | ||
next(symbols.TASK_CANCEL); | ||
@@ -656,26 +1105,2 @@ } | ||
/** | ||
This may be called by a parent generator to trigger/propagate cancellation | ||
cancel all pending tasks (including the main task), then end the current task. | ||
Cancellation propagates down to the whole execution tree holded by this Parent task | ||
It's also propagated to all joiners of this task and their execution tree/joiners | ||
Cancellation is noop for terminated/Cancelled tasks tasks | ||
**/ | ||
function cancel() { | ||
/** | ||
We need to check both Running and Cancelled status | ||
Tasks can be Cancelled but still Running | ||
**/ | ||
if (task._isRunning && !task._isCancelled) { | ||
task._isCancelled = true; | ||
taskQueue.cancelAll(); | ||
/** | ||
Ending with a Never result will propagate the Cancellation to all joiners | ||
**/ | ||
end(symbols.TASK_CANCEL); | ||
} | ||
} | ||
/** | ||
attaches cancellation logic to this task's continuation | ||
@@ -686,3 +1111,3 @@ this will permit cancellation to propagate down the call chain | ||
cont && (cont.cancel = cancel); // kicks up the generator | ||
cont.cancel = task.cancel; // kicks up the generator | ||
@@ -693,13 +1118,12 @@ next(); // then return the task descriptor to the caller | ||
/** | ||
This is the generator driver | ||
It's a recursive async/continuation function which calls itself | ||
until the generator terminates or throws | ||
**/ | ||
* This is the generator driver | ||
* It's a recursive async/continuation function which calls itself | ||
* until the generator terminates or throws | ||
* @param {internal commands(TASK_CANCEL | TERMINATE) | any} arg - value, generator will be resumed with. | ||
* @param {boolean} isErr - the flag shows if effect finished with an error | ||
* | ||
* receives either (command | effect result, false) or (any thrown thing, true) | ||
*/ | ||
function next(arg, isErr) { | ||
// Preventive measure. If we end up here, then there is really something wrong | ||
if (!mainTask._isRunning) { | ||
throw new Error('Trying to resume an already finished generator'); | ||
} | ||
try { | ||
@@ -709,3 +1133,5 @@ var result; | ||
if (isErr) { | ||
result = iterator.throw(arg); | ||
result = iterator.throw(arg); // user handled the error, we can clear bookkept values | ||
clear(); | ||
} else if (__chunk_1.shouldCancel(arg)) { | ||
@@ -718,3 +1144,3 @@ /** | ||
**/ | ||
mainTask._isCancelled = true; | ||
mainTask.status = CANCELLED; | ||
/** | ||
@@ -744,3 +1170,3 @@ Cancels the current effect; this will propagate the cancellation down to any called tasks | ||
if (!result.done) { | ||
digestEffect(result.value, parentEffectId, '', next); | ||
digestEffect(result.value, parentEffectId, next); | ||
} else { | ||
@@ -750,11 +1176,14 @@ /** | ||
**/ | ||
mainTask._isRunning = false; | ||
if (mainTask.status !== CANCELLED) { | ||
mainTask.status = DONE; | ||
} | ||
mainTask.cont(result.value); | ||
} | ||
} catch (error) { | ||
if (mainTask._isCancelled) { | ||
env.logError(error); | ||
if (mainTask.status === CANCELLED) { | ||
throw error; | ||
} | ||
mainTask._isRunning = false; | ||
mainTask.status = ABORTED; | ||
mainTask.cont(error, true); | ||
@@ -764,40 +1193,2 @@ } | ||
function end(result, isErr) { | ||
task._isRunning = false; | ||
if (!isErr) { | ||
task._result = result; | ||
task._deferredEnd && task._deferredEnd.resolve(result); | ||
} else { | ||
addSagaStack(result, { | ||
meta: meta, | ||
effect: crashedEffect, | ||
cancelledTasks: cancelledDueToErrorTasks | ||
}); | ||
if (!task.cont) { | ||
if (result && result.sagaStack) { | ||
result.sagaStack = sagaStackToString(result.sagaStack); | ||
} | ||
if (env.onError) { | ||
env.onError(result); | ||
} else { | ||
// TODO: could we skip this when _deferredEnd is attached? | ||
env.logError(result); | ||
} | ||
} | ||
task._error = result; | ||
task._isAborted = true; | ||
task._deferredEnd && task._deferredEnd.reject(result); | ||
} | ||
task.cont && task.cont(result, isErr); | ||
task.joiners.forEach(function (j) { | ||
return j.cb(result, isErr); | ||
}); | ||
task.joiners = null; | ||
} | ||
function runEffect(effect, effectId, currCb) { | ||
@@ -819,7 +1210,9 @@ /** | ||
} else if (is.iterator(effect)) { | ||
resolveIterator(effect, effectId, meta, currCb); | ||
// resolve iterator | ||
proc(env, effect, task.context, effectId, meta, | ||
/* isRoot */ | ||
false, currCb); | ||
} else if (effect && effect[symbols.IO]) { | ||
var type = effect.type, | ||
payload = effect.payload; | ||
if (type === __chunk_2.TAKE) runTakeEffect(payload, currCb);else if (type === __chunk_2.PUT) runPutEffect(payload, currCb);else if (type === __chunk_2.ALL) runAllEffect(payload, effectId, currCb);else if (type === __chunk_2.RACE) runRaceEffect(payload, effectId, currCb);else if (type === __chunk_2.CALL) runCallEffect(payload, effectId, currCb);else if (type === __chunk_2.CPS) runCPSEffect(payload, currCb);else if (type === __chunk_2.FORK) runForkEffect(payload, effectId, currCb);else if (type === __chunk_2.JOIN) runJoinEffect(payload, currCb);else if (type === __chunk_2.CANCEL) runCancelEffect(payload, currCb);else if (type === __chunk_2.SELECT) runSelectEffect(payload, currCb);else if (type === __chunk_2.ACTION_CHANNEL) runChannelEffect(payload, currCb);else if (type === __chunk_2.FLUSH) runFlushEffect(payload, currCb);else if (type === __chunk_2.CANCELLED) runCancelledEffect(payload, currCb);else if (type === __chunk_2.GET_CONTEXT) runGetContextEffect(payload, currCb);else if (type === __chunk_2.SET_CONTEXT) runSetContextEffect(payload, currCb);else currCb(effect); | ||
var effectRunner = effectRunnerMap[effect.type]; | ||
effectRunner(env, effect.payload, currCb, executingContext); | ||
} else { | ||
@@ -831,3 +1224,3 @@ // anything else returned as is | ||
function digestEffect(effect, parentEffectId, label, cb) { | ||
function digestEffect(effect, parentEffectId, cb, label) { | ||
if (label === void 0) { | ||
@@ -837,3 +1230,3 @@ label = ''; | ||
var effectId = __chunk_1.uid(); | ||
var effectId = nextEffectId(); | ||
env.sagaMonitor && env.sagaMonitor.effectTriggered({ | ||
@@ -870,3 +1263,3 @@ effectId: effectId, | ||
if (isErr) { | ||
crashedEffect = effect; | ||
setCrashedEffect(effect); | ||
} | ||
@@ -887,14 +1280,4 @@ | ||
effectSettled = true; | ||
/** | ||
propagates cancel downward | ||
catch uncaught cancellations errors; since we can no longer call the completion | ||
callback, log errors raised during cancellations into the console | ||
**/ | ||
currCb.cancel(); // propagates cancel downward | ||
try { | ||
currCb.cancel(); | ||
} catch (err) { | ||
env.logError(err); | ||
} | ||
currCb.cancel = __chunk_1.noop; // defensive measure | ||
@@ -907,378 +1290,2 @@ | ||
} | ||
function resolvePromise(promise, cb) { | ||
var cancelPromise = promise[symbols.CANCEL]; | ||
if (is.func(cancelPromise)) { | ||
cb.cancel = cancelPromise; | ||
} else if (is.func(promise.abort)) { | ||
cb.cancel = function () { | ||
return promise.abort(); | ||
}; | ||
} | ||
promise.then(cb, function (error) { | ||
return cb(error, true); | ||
}); | ||
} | ||
function resolveIterator(iterator, effectId, meta, cb) { | ||
proc(env, iterator, taskContext, effectId, meta, cb); | ||
} | ||
function runTakeEffect(_ref2, cb) { | ||
var _ref2$channel = _ref2.channel, | ||
channel$$1 = _ref2$channel === void 0 ? env.stdChannel : _ref2$channel, | ||
pattern = _ref2.pattern, | ||
maybe = _ref2.maybe; | ||
var takeCb = function takeCb(input) { | ||
if (input instanceof Error) { | ||
cb(input, true); | ||
return; | ||
} | ||
if (isEnd(input) && !maybe) { | ||
cb(symbols.TERMINATE); | ||
return; | ||
} | ||
cb(input); | ||
}; | ||
try { | ||
channel$$1.take(takeCb, is.notUndef(pattern) ? matcher(pattern) : null); | ||
} catch (err) { | ||
cb(err, true); | ||
return; | ||
} | ||
cb.cancel = takeCb.cancel; | ||
} | ||
function runPutEffect(_ref3, cb) { | ||
var channel$$1 = _ref3.channel, | ||
action = _ref3.action, | ||
resolve = _ref3.resolve; | ||
/** | ||
Schedule the put in case another saga is holding a lock. | ||
The put will be executed atomically. ie nested puts will execute after | ||
this put has terminated. | ||
**/ | ||
asap(function () { | ||
var result; | ||
try { | ||
result = (channel$$1 ? channel$$1.put : env.dispatch)(action); | ||
} catch (error) { | ||
cb(error, true); | ||
return; | ||
} | ||
if (resolve && is.promise(result)) { | ||
resolvePromise(result, cb); | ||
} else { | ||
cb(result); | ||
} | ||
}); // Put effects are non cancellables | ||
} | ||
function runCallEffect(_ref4, effectId, cb) { | ||
var context = _ref4.context, | ||
fn = _ref4.fn, | ||
args = _ref4.args; | ||
// catch synchronous failures; see #152 | ||
try { | ||
var result = fn.apply(context, args); | ||
if (is.promise(result)) { | ||
resolvePromise(result, cb); | ||
return; | ||
} | ||
if (is.iterator(result)) { | ||
resolveIterator(result, effectId, getMetaInfo(fn), cb); | ||
return; | ||
} | ||
cb(result); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runCPSEffect(_ref5, cb) { | ||
var context = _ref5.context, | ||
fn = _ref5.fn, | ||
args = _ref5.args; | ||
// CPS (ie node style functions) can define their own cancellation logic | ||
// by setting cancel field on the cb | ||
// catch synchronous failures; see #152 | ||
try { | ||
var cpsCb = function cpsCb(err, res) { | ||
return is.undef(err) ? cb(res) : cb(err, true); | ||
}; | ||
fn.apply(context, args.concat(cpsCb)); | ||
if (cpsCb.cancel) { | ||
cb.cancel = function () { | ||
return cpsCb.cancel(); | ||
}; | ||
} | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runForkEffect(_ref6, effectId, cb) { | ||
var context = _ref6.context, | ||
fn = _ref6.fn, | ||
args = _ref6.args, | ||
detached = _ref6.detached; | ||
var taskIterator = createTaskIterator({ | ||
context: context, | ||
fn: fn, | ||
args: args | ||
}); | ||
var meta = getIteratorMetaInfo(taskIterator, fn); | ||
try { | ||
suspend(); | ||
var _task = proc(env, taskIterator, taskContext, effectId, meta, detached ? null : __chunk_1.noop); | ||
if (detached) { | ||
cb(_task); | ||
} else { | ||
if (_task._isRunning) { | ||
taskQueue.addTask(_task); | ||
cb(_task); | ||
} else if (_task._error) { | ||
taskQueue.abort(_task._error); | ||
} else { | ||
cb(_task); | ||
} | ||
} | ||
} finally { | ||
flush(); | ||
} // Fork effects are non cancellables | ||
} | ||
function runJoinEffect(taskOrTasks, cb) { | ||
if (is.array(taskOrTasks)) { | ||
if (taskOrTasks.length === 0) { | ||
cb([]); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(taskOrTasks, cb); | ||
taskOrTasks.forEach(function (t, i) { | ||
joinSingleTask(t, childCallbacks[i]); | ||
}); | ||
} else { | ||
joinSingleTask(taskOrTasks, cb); | ||
} | ||
} | ||
function joinSingleTask(taskToJoin, cb) { | ||
if (taskToJoin.isRunning()) { | ||
var joiner = { | ||
task: task, | ||
cb: cb | ||
}; | ||
cb.cancel = function () { | ||
return __chunk_1.remove(taskToJoin.joiners, joiner); | ||
}; | ||
taskToJoin.joiners.push(joiner); | ||
} else { | ||
if (taskToJoin.isAborted()) { | ||
cb(taskToJoin.error(), true); | ||
} else { | ||
cb(taskToJoin.result()); | ||
} | ||
} | ||
} | ||
function runCancelEffect(taskOrTasks, cb) { | ||
if (taskOrTasks === symbols.SELF_CANCELLATION) { | ||
cancelSingleTask(task); | ||
} else if (is.array(taskOrTasks)) { | ||
taskOrTasks.forEach(cancelSingleTask); | ||
} else { | ||
cancelSingleTask(taskOrTasks); | ||
} | ||
cb(); // cancel effects are non cancellables | ||
} | ||
function cancelSingleTask(taskToCancel) { | ||
if (taskToCancel.isRunning()) { | ||
taskToCancel.cancel(); | ||
} | ||
} | ||
function runAllEffect(effects, effectId, cb) { | ||
var keys = Object.keys(effects); | ||
if (keys.length === 0) { | ||
cb(is.array(effects) ? [] : {}); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(effects, cb); | ||
keys.forEach(function (key) { | ||
return digestEffect(effects[key], effectId, key, childCallbacks[key]); | ||
}); | ||
} | ||
function runRaceEffect(effects, effectId, cb) { | ||
var completed; | ||
var keys = Object.keys(effects); | ||
var childCbs = {}; | ||
keys.forEach(function (key) { | ||
var chCbAtKey = function chCbAtKey(res, isErr) { | ||
if (completed) { | ||
return; | ||
} | ||
if (isErr || __chunk_1.shouldComplete(res)) { | ||
// Race Auto cancellation | ||
cb.cancel(); | ||
cb(res, isErr); | ||
} else { | ||
var _response; | ||
cb.cancel(); | ||
completed = true; | ||
var response = (_response = {}, _response[key] = res, _response); | ||
cb(is.array(effects) ? __chunk_1.array.from(_extends({}, response, { | ||
length: keys.length | ||
})) : response); | ||
} | ||
}; | ||
chCbAtKey.cancel = __chunk_1.noop; | ||
childCbs[key] = chCbAtKey; | ||
}); | ||
cb.cancel = function () { | ||
// prevents unnecessary cancellation | ||
if (!completed) { | ||
completed = true; | ||
keys.forEach(function (key) { | ||
return childCbs[key].cancel(); | ||
}); | ||
} | ||
}; | ||
keys.forEach(function (key) { | ||
if (completed) { | ||
return; | ||
} | ||
digestEffect(effects[key], effectId, key, childCbs[key]); | ||
}); | ||
} | ||
function runSelectEffect(_ref7, cb) { | ||
var selector = _ref7.selector, | ||
args = _ref7.args; | ||
try { | ||
var state = selector.apply(void 0, [env.getState()].concat(args)); | ||
cb(state); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runChannelEffect(_ref8, cb) { | ||
var pattern = _ref8.pattern, | ||
buffer = _ref8.buffer; | ||
// TODO: rethink how END is handled | ||
var chan = channel(buffer); | ||
var match = matcher(pattern); | ||
var taker = function taker(action) { | ||
if (!isEnd(action)) { | ||
env.stdChannel.take(taker, match); | ||
} | ||
chan.put(action); | ||
}; | ||
var close = chan.close; | ||
chan.close = function () { | ||
taker.cancel(); | ||
close(); | ||
}; | ||
env.stdChannel.take(taker, match); | ||
cb(chan); | ||
} | ||
function runCancelledEffect(data, cb) { | ||
cb(Boolean(mainTask._isCancelled)); | ||
} | ||
function runFlushEffect(channel$$1, cb) { | ||
channel$$1.flush(cb); | ||
} | ||
function runGetContextEffect(prop, cb) { | ||
cb(taskContext[prop]); | ||
} | ||
function runSetContextEffect(props, cb) { | ||
__chunk_1.assignWithSymbols(taskContext, props); | ||
cb(); | ||
} | ||
function newTask(id, meta, cont) { | ||
var _task2; | ||
var task = (_task2 = {}, _task2[symbols.TASK] = true, _task2.id = id, _task2.meta = meta, _task2._deferredEnd = null, _task2.toPromise = function toPromise() { | ||
if (task._deferredEnd) { | ||
return task._deferredEnd.promise; | ||
} | ||
var def = deferred(); | ||
task._deferredEnd = def; | ||
if (!task._isRunning) { | ||
if (task._isAborted) { | ||
def.reject(task._error); | ||
} else { | ||
def.resolve(task._result); | ||
} | ||
} | ||
return def.promise; | ||
}, _task2.cont = cont, _task2.joiners = [], _task2.cancel = cancel, _task2._isRunning = true, _task2._isCancelled = false, _task2._isAborted = false, _task2._result = undefined, _task2._error = undefined, _task2.isRunning = function isRunning() { | ||
return task._isRunning; | ||
}, _task2.isCancelled = function isCancelled() { | ||
return task._isCancelled; | ||
}, _task2.isAborted = function isAborted() { | ||
return task._isAborted; | ||
}, _task2.result = function result() { | ||
return task._result; | ||
}, _task2.error = function error() { | ||
return task._error; | ||
}, _task2.setContext = function setContext(props) { | ||
{ | ||
__chunk_1.check(props, is.object, __chunk_1.createSetContextWarning('task', props)); | ||
} | ||
__chunk_1.assignWithSymbols(taskContext, props); | ||
}, _task2); | ||
return task; | ||
} | ||
} | ||
@@ -1288,3 +1295,14 @@ | ||
var NON_GENERATOR_ERR = RUN_SAGA_SIGNATURE + ": saga argument must be a Generator function!"; | ||
function runSaga(options, saga) { | ||
function runSaga(_ref, saga) { | ||
var _ref$channel = _ref.channel, | ||
channel$$1 = _ref$channel === void 0 ? stdChannel() : _ref$channel, | ||
dispatch = _ref.dispatch, | ||
getState = _ref.getState, | ||
_ref$context = _ref.context, | ||
context = _ref$context === void 0 ? {} : _ref$context, | ||
sagaMonitor = _ref.sagaMonitor, | ||
effectMiddlewares = _ref.effectMiddlewares, | ||
_ref$onError = _ref.onError, | ||
onError = _ref$onError === void 0 ? __chunk_1.logError : _ref$onError; | ||
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { | ||
@@ -1304,13 +1322,3 @@ args[_key - 2] = arguments[_key]; | ||
var _options$channel = options.channel, | ||
channel$$1 = _options$channel === void 0 ? stdChannel() : _options$channel, | ||
dispatch = options.dispatch, | ||
getState = options.getState, | ||
_options$context = options.context, | ||
context = _options$context === void 0 ? {} : _options$context, | ||
sagaMonitor = options.sagaMonitor, | ||
logger = options.logger, | ||
effectMiddlewares = options.effectMiddlewares, | ||
onError = options.onError; | ||
var effectId = __chunk_1.uid(); | ||
var effectId = nextEffectId(); | ||
@@ -1332,31 +1340,29 @@ if (sagaMonitor) { | ||
if (is.notUndef(effectMiddlewares)) { | ||
var MIDDLEWARE_TYPE_ERROR = 'effectMiddlewares must be an array of functions'; | ||
__chunk_1.check(effectMiddlewares, is.array, MIDDLEWARE_TYPE_ERROR); | ||
effectMiddlewares.forEach(function (effectMiddleware) { | ||
return __chunk_1.check(effectMiddleware, is.func, MIDDLEWARE_TYPE_ERROR); | ||
}); | ||
} | ||
{ | ||
if (is.notUndef(onError)) { | ||
__chunk_1.check(onError, is.func, 'onError must be a function'); | ||
if (is.notUndef(dispatch)) { | ||
__chunk_1.check(dispatch, is.func, 'dispatch must be a function'); | ||
} | ||
} | ||
var log = logger || __chunk_1.log; | ||
if (is.notUndef(getState)) { | ||
__chunk_1.check(getState, is.func, 'getState must be a function'); | ||
} | ||
var logError = function logError(err) { | ||
log('error', err); | ||
if (err && err.sagaStack) { | ||
log('error', err.sagaStack); | ||
if (is.notUndef(effectMiddlewares)) { | ||
var MIDDLEWARE_TYPE_ERROR = 'effectMiddlewares must be an array of functions'; | ||
__chunk_1.check(effectMiddlewares, is.array, MIDDLEWARE_TYPE_ERROR); | ||
effectMiddlewares.forEach(function (effectMiddleware) { | ||
return __chunk_1.check(effectMiddleware, is.func, MIDDLEWARE_TYPE_ERROR); | ||
}); | ||
} | ||
}; | ||
var middleware = effectMiddlewares && redux.compose.apply(void 0, effectMiddlewares); | ||
__chunk_1.check(onError, is.func, 'onError passed to the redux-saga is not a function!'); | ||
} | ||
var finalizeRunEffect = function finalizeRunEffect(runEffect) { | ||
if (is.func(middleware)) { | ||
return function finalRunEffect(effect, effectId, currCb) { | ||
var finalizeRunEffect; | ||
if (effectMiddlewares) { | ||
var middleware = redux.compose.apply(void 0, effectMiddlewares); | ||
finalizeRunEffect = function finalizeRunEffect(runEffect) { | ||
return function (effect, effectId, currCb) { | ||
var plainRunEffect = function plainRunEffect(eff) { | ||
@@ -1368,21 +1374,20 @@ return runEffect(eff, effectId, currCb); | ||
}; | ||
} else { | ||
return runEffect; | ||
} | ||
}; | ||
}; | ||
} else { | ||
finalizeRunEffect = __chunk_1.identity; | ||
} | ||
var env = { | ||
stdChannel: channel$$1, | ||
channel: channel$$1, | ||
dispatch: __chunk_1.wrapSagaDispatch(dispatch), | ||
getState: getState, | ||
sagaMonitor: sagaMonitor, | ||
logError: logError, | ||
onError: onError, | ||
finalizeRunEffect: finalizeRunEffect | ||
}; | ||
return immediately(function () { | ||
var task = proc(env, iterator, context, effectId, __chunk_1.getMetaInfo(saga), | ||
/* isRoot */ | ||
true, __chunk_1.noop); | ||
try { | ||
suspend(); | ||
var task = proc(env, iterator, context, effectId, getMetaInfo(saga), null); | ||
if (sagaMonitor) { | ||
@@ -1393,5 +1398,3 @@ sagaMonitor.effectResolved(effectId, task); | ||
return task; | ||
} finally { | ||
flush(); | ||
} | ||
}); | ||
} | ||
@@ -1407,22 +1410,11 @@ | ||
context = _ref2$context === void 0 ? {} : _ref2$context, | ||
options = _objectWithoutPropertiesLoose(_ref2, ["context"]); | ||
_ref2$channel = _ref2.channel, | ||
channel$$1 = _ref2$channel === void 0 ? stdChannel() : _ref2$channel, | ||
sagaMonitor = _ref2.sagaMonitor, | ||
options = _objectWithoutPropertiesLoose(_ref2, ["context", "channel", "sagaMonitor"]); | ||
var sagaMonitor = options.sagaMonitor, | ||
logger = options.logger, | ||
onError = options.onError, | ||
effectMiddlewares = options.effectMiddlewares; | ||
var boundRunSaga; | ||
{ | ||
if (is.notUndef(logger)) { | ||
__chunk_1.check(logger, is.func, 'options.logger passed to the Saga middleware is not a function!'); | ||
} | ||
if (is.notUndef(onError)) { | ||
__chunk_1.check(onError, is.func, 'options.onError passed to the Saga middleware is not a function!'); | ||
} | ||
if (is.notUndef(options.emitter)) { | ||
__chunk_1.check(options.emitter, is.func, 'options.emitter passed to the Saga middleware is not a function!'); | ||
} | ||
__chunk_1.check(channel$$1, is.channel, 'options.channel passed to the Saga middleware is not a channel'); | ||
} | ||
@@ -1433,5 +1425,3 @@ | ||
dispatch = _ref3.dispatch; | ||
var channel$$1 = stdChannel(); | ||
channel$$1.put = (options.emitter || __chunk_1.identity)(channel$$1.put); | ||
boundRunSaga = runSaga.bind(null, { | ||
boundRunSaga = runSaga.bind(null, _extends({}, options, { | ||
context: context, | ||
@@ -1441,7 +1431,4 @@ channel: channel$$1, | ||
getState: getState, | ||
sagaMonitor: sagaMonitor, | ||
logger: logger, | ||
onError: onError, | ||
effectMiddlewares: effectMiddlewares | ||
}); | ||
sagaMonitor: sagaMonitor | ||
})); | ||
return function (next) { | ||
@@ -1480,6 +1467,6 @@ return function (action) { | ||
exports.buffers = __chunk_1.buffers; | ||
exports.detach = __chunk_1.detach; | ||
exports.CANCEL = symbols.CANCEL; | ||
exports.SAGA_LOCATION = symbols.SAGA_LOCATION; | ||
exports.buffers = __chunk_2.buffers; | ||
exports.detach = __chunk_2.detach; | ||
exports.default = sagaMiddlewareFactory; | ||
@@ -1486,0 +1473,0 @@ exports.runSaga = runSaga; |
@@ -1,10 +0,9 @@ | ||
import { notUndef, func, object, iterator, array, buffer, pattern, multicast, channel, undef, string, task, stringableFunc, symbol, promise } from '@redux-saga/is'; | ||
import { a as kTrue, c as check, f as remove, g as once, h as internalErr, b as noop, i as uid, j as array$1, k as assignWithSymbols, l as makeIterator, d as createSetContextWarning, m as shouldCancel, n as shouldTerminate, o as createAllStyleChildCallbacks, p as shouldComplete, q as asyncIteratorSymbol, r as wrapSagaDispatch, s as log, e as identity } from './chunk-e16e13ae.js'; | ||
import { CHANNEL_END_TYPE, MATCH, MULTICAST, SAGA_ACTION, SAGA_LOCATION, CANCEL, IO, TERMINATE, TASK, TASK_CANCEL, SELF_CANCELLATION } from '@redux-saga/symbols'; | ||
import { channel, object, func, iterator, notUndef, array, buffer, pattern, multicast, undef, string, task, promise, stringableFunc, symbol } from '@redux-saga/is'; | ||
import { a as kTrue, b as check, c as remove, d as once, e as internalErr, f as none, g as fixed, h as dropping, i as sliding, j as expanding, k as buffers, l as TAKE, m as PUT, n as ALL, o as RACE, p as CALL, q as CPS, r as FORK, s as JOIN, t as CANCEL$1, u as SELECT, v as ACTION_CHANNEL, w as CANCELLED, x as FLUSH, y as GET_CONTEXT, z as SET_CONTEXT, A as effectTypes, B as assignWithSymbols, C as createAllStyleChildCallbacks, D as createEmptyArray, E as makeIterator, F as noop, G as shouldComplete, H as getMetaInfo, I as getLocation, J as flatMap, K as createSetContextWarning, L as asyncIteratorSymbol, M as shouldCancel, N as shouldTerminate, O as logError, P as wrapSagaDispatch, Q as identity } from './chunk-b503a2ff.js'; | ||
export { k as buffers, Y as detach } from './chunk-b503a2ff.js'; | ||
import { CHANNEL_END_TYPE, MATCH, MULTICAST, SAGA_ACTION, CANCEL, SELF_CANCELLATION, TERMINATE, TASK, TASK_CANCEL, IO } from '@redux-saga/symbols'; | ||
export { CANCEL, SAGA_LOCATION } from '@redux-saga/symbols'; | ||
import { a as none, b as fixed, c as dropping, d as sliding, e as expanding, f as buffers, g as TAKE, h as PUT, i as ALL, j as RACE, k as CALL, l as CPS, m as FORK, n as JOIN, o as CANCEL$1, p as SELECT, q as ACTION_CHANNEL, r as CANCELLED, s as FLUSH, t as GET_CONTEXT, u as SET_CONTEXT, v as effectTypes } from './chunk-7bc4cf1d.js'; | ||
export { f as buffers, D as detach } from './chunk-7bc4cf1d.js'; | ||
import _extends from '@babel/runtime/helpers/esm/extends'; | ||
import deferred from '@redux-saga/deferred'; | ||
import { compose } from 'redux'; | ||
import _extends from '@babel/runtime/helpers/esm/extends'; | ||
import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/esm/objectWithoutPropertiesLoose'; | ||
@@ -51,2 +50,14 @@ import '@redux-saga/delay-p'; | ||
/** | ||
* Puts the scheduler in a `suspended` state and executes a task immediately. | ||
*/ | ||
function immediately(task$$1) { | ||
try { | ||
suspend(); | ||
return task$$1(); | ||
} finally { | ||
flush(); | ||
} | ||
} | ||
/** | ||
Puts the scheduler in a `suspended` state. Scheduled tasks will be queued until the | ||
@@ -63,2 +74,3 @@ scheduler is released. | ||
function release() { | ||
@@ -81,3 +93,3 @@ semaphore--; | ||
var array$2 = function array$$1(patterns) { | ||
var array$1 = function array$$1(patterns) { | ||
return function (input) { | ||
@@ -109,3 +121,3 @@ return patterns.some(function (p) { | ||
// prettier-ignore | ||
var matcherCreator = pattern$$1 === '*' ? wildcard : string(pattern$$1) ? string$1 : array(pattern$$1) ? array$2 : stringableFunc(pattern$$1) ? string$1 : func(pattern$$1) ? predicate : symbol(pattern$$1) ? symbol$1 : null; | ||
var matcherCreator = pattern$$1 === '*' ? wildcard : string(pattern$$1) ? string$1 : array(pattern$$1) ? array$1 : stringableFunc(pattern$$1) ? string$1 : func(pattern$$1) ? predicate : symbol(pattern$$1) ? symbol$1 : null; | ||
@@ -187,3 +199,3 @@ if (matcherCreator === null) { | ||
function flush$$1(cb) { | ||
function flush(cb) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
@@ -224,3 +236,3 @@ checkForbiddenStates(); | ||
put: put, | ||
flush: flush$$1, | ||
flush: flush, | ||
close: close | ||
@@ -377,127 +389,416 @@ }; | ||
function formatLocation(fileName, lineNumber) { | ||
return fileName + "?" + lineNumber; | ||
var RUNNING = 0; | ||
var CANCELLED$1 = 1; | ||
var ABORTED = 2; | ||
var DONE = 3; | ||
function resolvePromise(promise$$1, cb) { | ||
var cancelPromise = promise$$1[CANCEL]; | ||
if (func(cancelPromise)) { | ||
cb.cancel = cancelPromise; | ||
} | ||
promise$$1.then(cb, function (error) { | ||
cb(error, true); | ||
}); | ||
} | ||
function getLocation(instrumented) { | ||
return instrumented[SAGA_LOCATION]; | ||
var current = 0; | ||
var nextEffectId = (function () { | ||
return ++current; | ||
}); | ||
var _effectRunnerMap; | ||
function getIteratorMetaInfo(iterator$$1, fn) { | ||
if (iterator$$1.isSagaIterator) { | ||
return { | ||
name: iterator$$1.meta.name | ||
}; | ||
} | ||
return getMetaInfo(fn); | ||
} | ||
function effectLocationAsString(effect) { | ||
var location = getLocation(effect); | ||
function createTaskIterator(_ref) { | ||
var context = _ref.context, | ||
fn = _ref.fn, | ||
args = _ref.args; | ||
if (location) { | ||
var code = location.code, | ||
fileName = location.fileName, | ||
lineNumber = location.lineNumber; | ||
var source = code + " " + formatLocation(fileName, lineNumber); | ||
return source; | ||
// catch synchronous failures; see #152 and #441 | ||
try { | ||
var result = fn.apply(context, args); // i.e. a generator function returns an iterator | ||
if (iterator(result)) { | ||
return result; | ||
} | ||
var next = function next(value) { | ||
if (value === void 0) { | ||
value = result; | ||
} | ||
return { | ||
value: value, | ||
done: !promise(value) | ||
}; | ||
}; | ||
return makeIterator(next); | ||
} catch (err) { | ||
// do not bubble up synchronous failures for detached forks | ||
// instead create a failed task. See #152 and #441 | ||
return makeIterator(function () { | ||
throw err; | ||
}); | ||
} | ||
} | ||
return ''; | ||
function runPutEffect(env, _ref2, cb) { | ||
var channel$$1 = _ref2.channel, | ||
action = _ref2.action, | ||
resolve = _ref2.resolve; | ||
/** | ||
Schedule the put in case another saga is holding a lock. | ||
The put will be executed atomically. ie nested puts will execute after | ||
this put has terminated. | ||
**/ | ||
asap(function () { | ||
var result; | ||
try { | ||
result = (channel$$1 ? channel$$1.put : env.dispatch)(action); | ||
} catch (error) { | ||
cb(error, true); | ||
return; | ||
} | ||
if (resolve && promise(result)) { | ||
resolvePromise(result, cb); | ||
} else { | ||
cb(result); | ||
} | ||
}); // Put effects are non cancellables | ||
} | ||
function sagaLocationAsString(sagaMeta) { | ||
var name = sagaMeta.name, | ||
location = sagaMeta.location; | ||
function runTakeEffect(env, _ref3, cb) { | ||
var _ref3$channel = _ref3.channel, | ||
channel$$1 = _ref3$channel === void 0 ? env.channel : _ref3$channel, | ||
pattern$$1 = _ref3.pattern, | ||
maybe = _ref3.maybe; | ||
if (location) { | ||
return name + " " + formatLocation(location.fileName, location.lineNumber); | ||
var takeCb = function takeCb(input) { | ||
if (input instanceof Error) { | ||
cb(input, true); | ||
return; | ||
} | ||
if (isEnd(input) && !maybe) { | ||
cb(TERMINATE); | ||
return; | ||
} | ||
cb(input); | ||
}; | ||
try { | ||
channel$$1.take(takeCb, notUndef(pattern$$1) ? matcher(pattern$$1) : null); | ||
} catch (err) { | ||
cb(err, true); | ||
return; | ||
} | ||
return name; | ||
cb.cancel = takeCb.cancel; | ||
} | ||
var flatMap = function flatMap(mapper, arr) { | ||
var _ref; | ||
function runCallEffect(env, _ref4, cb, _ref5) { | ||
var context = _ref4.context, | ||
fn = _ref4.fn, | ||
args = _ref4.args; | ||
var task$$1 = _ref5.task; | ||
return (_ref = []).concat.apply(_ref, arr.map(mapper)); | ||
}; | ||
// catch synchronous failures; see #152 | ||
try { | ||
var result = fn.apply(context, args); | ||
function cancelledTasksAsString(sagaStack) { | ||
var cancelledTasks = flatMap(function (i) { | ||
return i.cancelledTasks; | ||
}, sagaStack); | ||
if (promise(result)) { | ||
resolvePromise(result, cb); | ||
return; | ||
} | ||
if (!cancelledTasks.length) { | ||
return ''; | ||
if (iterator(result)) { | ||
// resolve iterator | ||
proc(env, result, task$$1.context, current, getMetaInfo(fn), | ||
/* isRoot */ | ||
false, cb); | ||
return; | ||
} | ||
cb(result); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
return ['Tasks cancelled due to error:'].concat(cancelledTasks).join('\n'); | ||
function runCPSEffect(env, _ref6, cb) { | ||
var context = _ref6.context, | ||
fn = _ref6.fn, | ||
args = _ref6.args; | ||
// CPS (ie node style functions) can define their own cancellation logic | ||
// by setting cancel field on the cb | ||
// catch synchronous failures; see #152 | ||
try { | ||
var cpsCb = function cpsCb(err, res) { | ||
if (undef(err)) { | ||
cb(res); | ||
} else { | ||
cb(err, true); | ||
} | ||
}; | ||
fn.apply(context, args.concat(cpsCb)); | ||
if (cpsCb.cancel) { | ||
cb.cancel = cpsCb.cancel; | ||
} | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
/** | ||
@param {saga, effect}[] sagaStack | ||
@returns {string} | ||
@example | ||
The above error occurred in task errorInPutSaga {pathToFile} | ||
when executing effect put({type: 'REDUCER_ACTION_ERROR_IN_PUT'}) {pathToFile} | ||
created by fetchSaga {pathToFile} | ||
created by rootSaga {pathToFile} | ||
*/ | ||
function runForkEffect(env, _ref7, cb, _ref8) { | ||
var context = _ref7.context, | ||
fn = _ref7.fn, | ||
args = _ref7.args, | ||
detached = _ref7.detached; | ||
var parent = _ref8.task; | ||
var taskIterator = createTaskIterator({ | ||
context: context, | ||
fn: fn, | ||
args: args | ||
}); | ||
var meta = getIteratorMetaInfo(taskIterator, fn); | ||
immediately(function () { | ||
var child = proc(env, taskIterator, parent.context, current, meta, detached, noop); | ||
if (detached) { | ||
cb(child); | ||
} else { | ||
if (child.isRunning()) { | ||
parent.queue.addTask(child); | ||
cb(child); | ||
} else if (child.isAborted()) { | ||
parent.queue.abort(child.error()); | ||
} else { | ||
cb(child); | ||
} | ||
} | ||
}); // Fork effects are non cancellables | ||
} | ||
function sagaStackToString(sagaStack) { | ||
var firstSaga = sagaStack[0], | ||
otherSagas = sagaStack.slice(1); | ||
var crashedEffectLocation = firstSaga.effect ? effectLocationAsString(firstSaga.effect) : null; | ||
var errorMessage = "The above error occurred in task " + sagaLocationAsString(firstSaga.meta) + (crashedEffectLocation ? " \n when executing effect " + crashedEffectLocation : ''); | ||
return [errorMessage].concat(otherSagas.map(function (s) { | ||
return " created by " + sagaLocationAsString(s.meta); | ||
}), [cancelledTasksAsString(sagaStack)]).join('\n'); | ||
function runJoinEffect(env, taskOrTasks, cb, _ref9) { | ||
var task$$1 = _ref9.task; | ||
var joinSingleTask = function joinSingleTask(taskToJoin, cb) { | ||
if (taskToJoin.isRunning()) { | ||
var joiner = { | ||
task: task$$1, | ||
cb: cb | ||
}; | ||
cb.cancel = function () { | ||
remove(taskToJoin.joiners, joiner); | ||
}; | ||
taskToJoin.joiners.push(joiner); | ||
} else { | ||
if (taskToJoin.isAborted()) { | ||
cb(taskToJoin.error(), true); | ||
} else { | ||
cb(taskToJoin.result()); | ||
} | ||
} | ||
}; | ||
if (array(taskOrTasks)) { | ||
if (taskOrTasks.length === 0) { | ||
cb([]); | ||
return; | ||
} | ||
var childCallbacks = createAllStyleChildCallbacks(taskOrTasks, cb); | ||
taskOrTasks.forEach(function (t, i) { | ||
joinSingleTask(t, childCallbacks[i]); | ||
}); | ||
} else { | ||
joinSingleTask(taskOrTasks, cb); | ||
} | ||
} | ||
function addSagaStack(errorObject, errorStack) { | ||
if (typeof errorObject === 'object') { | ||
if (typeof errorObject.sagaStack === 'undefined') { | ||
// property is used as a stack of descriptors for failed sagas | ||
// after formatting to string it will be re-written | ||
// to pass sagaStack as a string in user land | ||
Object.defineProperty(errorObject, 'sagaStack', { | ||
value: [], | ||
writable: true, | ||
enumerable: false | ||
function cancelSingleTask(taskToCancel) { | ||
if (taskToCancel.isRunning()) { | ||
taskToCancel.cancel(); | ||
} | ||
} | ||
function runCancelEffect(env, taskOrTasks, cb, _ref10) { | ||
var task$$1 = _ref10.task; | ||
if (taskOrTasks === SELF_CANCELLATION) { | ||
cancelSingleTask(task$$1); | ||
} else if (array(taskOrTasks)) { | ||
taskOrTasks.forEach(cancelSingleTask); | ||
} else { | ||
cancelSingleTask(taskOrTasks); | ||
} | ||
cb(); // cancel effects are non cancellables | ||
} | ||
function runAllEffect(env, effects, cb, _ref11) { | ||
var digestEffect = _ref11.digestEffect; | ||
var effectId = current; | ||
var keys = Object.keys(effects); | ||
if (keys.length === 0) { | ||
cb(array(effects) ? [] : {}); | ||
return; | ||
} | ||
var childCallbacks = createAllStyleChildCallbacks(effects, cb); | ||
keys.forEach(function (key) { | ||
digestEffect(effects[key], effectId, childCallbacks[key], key); | ||
}); | ||
} | ||
function runRaceEffect(env, effects, cb, _ref12) { | ||
var digestEffect = _ref12.digestEffect; | ||
var effectId = current; | ||
var keys = Object.keys(effects); | ||
var response = array(effects) ? createEmptyArray(keys.length) : {}; | ||
var childCbs = {}; | ||
var completed = false; | ||
keys.forEach(function (key) { | ||
var chCbAtKey = function chCbAtKey(res, isErr) { | ||
if (completed) { | ||
return; | ||
} | ||
if (isErr || shouldComplete(res)) { | ||
// Race Auto cancellation | ||
cb.cancel(); | ||
cb(res, isErr); | ||
} else { | ||
cb.cancel(); | ||
completed = true; | ||
response[key] = res; | ||
cb(response); | ||
} | ||
}; | ||
chCbAtKey.cancel = noop; | ||
childCbs[key] = chCbAtKey; | ||
}); | ||
cb.cancel = function () { | ||
// prevents unnecessary cancellation | ||
if (!completed) { | ||
completed = true; | ||
keys.forEach(function (key) { | ||
return childCbs[key].cancel(); | ||
}); | ||
} | ||
}; | ||
errorObject.sagaStack.push(errorStack); | ||
keys.forEach(function (key) { | ||
if (completed) { | ||
return; | ||
} | ||
digestEffect(effects[key], effectId, childCbs[key], key); | ||
}); | ||
} | ||
function runSelectEffect(env, _ref13, cb) { | ||
var selector = _ref13.selector, | ||
args = _ref13.args; | ||
try { | ||
var state = selector.apply(void 0, [env.getState()].concat(args)); | ||
cb(state); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function getMetaInfo(fn) { | ||
return { | ||
name: fn.name || 'anonymous', | ||
location: getLocation(fn) | ||
function runChannelEffect(env, _ref14, cb) { | ||
var pattern$$1 = _ref14.pattern, | ||
buffer$$1 = _ref14.buffer; | ||
var chan = channel$1(buffer$$1); | ||
var match = matcher(pattern$$1); | ||
var taker = function taker(action) { | ||
if (!isEnd(action)) { | ||
env.channel.take(taker, match); | ||
} | ||
chan.put(action); | ||
}; | ||
var close = chan.close; | ||
chan.close = function () { | ||
taker.cancel(); | ||
close(); | ||
}; | ||
env.channel.take(taker, match); | ||
cb(chan); | ||
} | ||
function getIteratorMetaInfo(iterator$$1, fn) { | ||
if (iterator$$1.isSagaIterator) { | ||
return { | ||
name: iterator$$1.meta.name | ||
}; | ||
} | ||
function runCancelledEffect(env, data, cb, _ref15) { | ||
var task$$1 = _ref15.task; | ||
cb(task$$1.isCancelled()); | ||
} | ||
return getMetaInfo(fn); | ||
function runFlushEffect(env, channel$$1, cb) { | ||
channel$$1.flush(cb); | ||
} | ||
function runGetContextEffect(env, prop, cb, _ref16) { | ||
var task$$1 = _ref16.task; | ||
cb(task$$1.context[prop]); | ||
} | ||
function runSetContextEffect(env, props, cb, _ref17) { | ||
var task$$1 = _ref17.task; | ||
assignWithSymbols(task$$1.context, props); | ||
cb(); | ||
} | ||
var effectRunnerMap = (_effectRunnerMap = {}, _effectRunnerMap[TAKE] = runTakeEffect, _effectRunnerMap[PUT] = runPutEffect, _effectRunnerMap[ALL] = runAllEffect, _effectRunnerMap[RACE] = runRaceEffect, _effectRunnerMap[CALL] = runCallEffect, _effectRunnerMap[CPS] = runCPSEffect, _effectRunnerMap[FORK] = runForkEffect, _effectRunnerMap[JOIN] = runJoinEffect, _effectRunnerMap[CANCEL$1] = runCancelEffect, _effectRunnerMap[SELECT] = runSelectEffect, _effectRunnerMap[ACTION_CHANNEL] = runChannelEffect, _effectRunnerMap[CANCELLED] = runCancelledEffect, _effectRunnerMap[FLUSH] = runFlushEffect, _effectRunnerMap[GET_CONTEXT] = runGetContextEffect, _effectRunnerMap[SET_CONTEXT] = runSetContextEffect, _effectRunnerMap); | ||
/** | ||
Used to track a parent task and its forks | ||
In the new fork model, forked tasks are attached by default to their parent | ||
We model this using the concept of Parent task && main Task | ||
main task is the main flow of the current Generator, the parent tasks is the | ||
aggregation of the main tasks + all its forked tasks. | ||
Thus the whole model represents an execution tree with multiple branches (vs the | ||
linear execution tree in sequential (non parallel) programming) | ||
Used to track a parent task and its forks | ||
In the fork model, forked tasks are attached by default to their parent | ||
We model this using the concept of Parent task && main Task | ||
main task is the main flow of the current Generator, the parent tasks is the | ||
aggregation of the main tasks + all its forked tasks. | ||
Thus the whole model represents an execution tree with multiple branches (vs the | ||
linear execution tree in sequential (non parallel) programming) | ||
A parent tasks has the following semantics | ||
- It completes if all its forks either complete or all cancelled | ||
- If it's cancelled, all forks are cancelled as well | ||
- It aborts if any uncaught error bubbles up from forks | ||
- If it completes, the return value is the one returned by the main task | ||
**/ | ||
A parent tasks has the following semantics | ||
- It completes if all its forks either complete or all cancelled | ||
- If it's cancelled, all forks are cancelled as well | ||
- It aborts if any uncaught error bubbles up from forks | ||
- If it completes, the return value is the one returned by the main task | ||
**/ | ||
function forkQueue(mainTask, onAbort, cb) { | ||
var tasks = [], | ||
result, | ||
completed = false; | ||
function forkQueue(mainTask, onAbort, cont) { | ||
var tasks = []; | ||
var result; | ||
var completed = false; | ||
addTask(mainTask); | ||
@@ -509,12 +810,6 @@ | ||
var getTaskNames = function getTaskNames() { | ||
return tasks.map(function (t) { | ||
return t.meta.name; | ||
}); | ||
}; | ||
function abort(err) { | ||
onAbort(); | ||
cancelAll(); | ||
cb(err, true); | ||
cont(err, true); | ||
} | ||
@@ -542,7 +837,6 @@ | ||
completed = true; | ||
cb(result); | ||
cont(result); | ||
} | ||
} | ||
}; // task.cont.cancel = task.cancel | ||
}; | ||
} | ||
@@ -567,42 +861,197 @@ | ||
abort: abort, | ||
getTasks: getTasks, | ||
getTaskNames: getTaskNames | ||
getTasks: getTasks | ||
}; | ||
} | ||
function createTaskIterator(_ref) { | ||
var context = _ref.context, | ||
fn = _ref.fn, | ||
args = _ref.args; | ||
// there can be only a single saga error created at any given moment | ||
// catch synchronous failures; see #152 and #441 | ||
try { | ||
var result = fn.apply(context, args); // i.e. a generator function returns an iterator | ||
function formatLocation(fileName, lineNumber) { | ||
return fileName + "?" + lineNumber; | ||
} | ||
if (iterator(result)) { | ||
return result; | ||
function effectLocationAsString(effect) { | ||
var location = getLocation(effect); | ||
if (location) { | ||
var code = location.code, | ||
fileName = location.fileName, | ||
lineNumber = location.lineNumber; | ||
var source = code + " " + formatLocation(fileName, lineNumber); | ||
return source; | ||
} | ||
return ''; | ||
} | ||
function sagaLocationAsString(sagaMeta) { | ||
var name = sagaMeta.name, | ||
location = sagaMeta.location; | ||
if (location) { | ||
return name + " " + formatLocation(location.fileName, location.lineNumber); | ||
} | ||
return name; | ||
} | ||
function cancelledTasksAsString(sagaStack) { | ||
var cancelledTasks = flatMap(function (i) { | ||
return i.cancelledTasks; | ||
}, sagaStack); | ||
if (!cancelledTasks.length) { | ||
return ''; | ||
} | ||
return ['Tasks cancelled due to error:'].concat(cancelledTasks).join('\n'); | ||
} | ||
var crashedEffect = null; | ||
var sagaStack = []; | ||
var addSagaFrame = function addSagaFrame(frame) { | ||
frame.crashedEffect = crashedEffect; | ||
sagaStack.push(frame); | ||
}; | ||
var clear = function clear() { | ||
crashedEffect = null; | ||
sagaStack.length = 0; | ||
}; // this sets crashed effect for the soon-to-be-reported saga frame | ||
// this slightly streatches the singleton nature of this module into wrong direction | ||
// as it's even less obvious what's the data flow here, but it is what it is for now | ||
var setCrashedEffect = function setCrashedEffect(effect) { | ||
crashedEffect = effect; | ||
}; | ||
/** | ||
@returns {string} | ||
@example | ||
The above error occurred in task errorInPutSaga {pathToFile} | ||
when executing effect put({type: 'REDUCER_ACTION_ERROR_IN_PUT'}) {pathToFile} | ||
created by fetchSaga {pathToFile} | ||
created by rootSaga {pathToFile} | ||
*/ | ||
var toString = function toString() { | ||
var firstSaga = sagaStack[0], | ||
otherSagas = sagaStack.slice(1); | ||
var crashedEffectLocation = firstSaga.crashedEffect ? effectLocationAsString(firstSaga.crashedEffect) : null; | ||
var errorMessage = "The above error occurred in task " + sagaLocationAsString(firstSaga.meta) + (crashedEffectLocation ? " \n when executing effect " + crashedEffectLocation : ''); | ||
return [errorMessage].concat(otherSagas.map(function (s) { | ||
return " created by " + sagaLocationAsString(s.meta); | ||
}), [cancelledTasksAsString(sagaStack)]).join('\n'); | ||
}; | ||
function newTask(env, mainTask, parentContext, parentEffectId, meta, isRoot, cont) { | ||
var _task; | ||
var status = RUNNING; | ||
var taskResult; | ||
var taskError; | ||
var deferredEnd = null; | ||
var cancelledDueToErrorTasks = []; | ||
var context = Object.create(parentContext); | ||
var queue = forkQueue(mainTask, function onAbort() { | ||
cancelledDueToErrorTasks.push.apply(cancelledDueToErrorTasks, queue.getTasks().map(function (t) { | ||
return t.meta.name; | ||
})); | ||
}, end); | ||
/** | ||
This may be called by a parent generator to trigger/propagate cancellation | ||
cancel all pending tasks (including the main task), then end the current task. | ||
Cancellation propagates down to the whole execution tree held by this Parent task | ||
It's also propagated to all joiners of this task and their execution tree/joiners | ||
Cancellation is noop for terminated/Cancelled tasks tasks | ||
**/ | ||
function cancel() { | ||
if (status === RUNNING) { | ||
// Setting status to CANCELLED does not necessarily mean that the task/iterators are stopped | ||
// effects in the iterator's finally block will still be executed | ||
status = CANCELLED$1; | ||
queue.cancelAll(); // Ending with a TASK_CANCEL will propagate the Cancellation to all joiners | ||
end(TASK_CANCEL, false); | ||
} | ||
} | ||
var next = function next(value) { | ||
if (value === void 0) { | ||
value = result; | ||
function end(result, isErr) { | ||
if (!isErr) { | ||
// The status here may be RUNNING or CANCELLED | ||
// If the status is CANCELLED, then we do not need to change it here | ||
if (result === TASK_CANCEL) { | ||
status = CANCELLED$1; | ||
} else if (status !== CANCELLED$1) { | ||
status = DONE; | ||
} | ||
return { | ||
value: value, | ||
done: !promise(value) | ||
}; | ||
}; | ||
taskResult = result; | ||
deferredEnd && deferredEnd.resolve(result); | ||
} else { | ||
status = ABORTED; | ||
addSagaFrame({ | ||
meta: meta, | ||
cancelledTasks: cancelledDueToErrorTasks | ||
}); | ||
return makeIterator(next); | ||
} catch (err) { | ||
// do not bubble up synchronous failures for detached forks | ||
// instead create a failed task. See #152 and #441 | ||
return makeIterator(function () { | ||
throw err; | ||
if (task$$1.isRoot) { | ||
var sagaStack = toString(); // we've dumped the saga stack to string and are passing it to user's code | ||
// we know that it won't be needed anymore and we need to clear it | ||
clear(); | ||
env.onError(result, { | ||
sagaStack: sagaStack | ||
}); | ||
} | ||
taskError = result; | ||
deferredEnd && deferredEnd.reject(result); | ||
} | ||
task$$1.cont(result, isErr); | ||
task$$1.joiners.forEach(function (joiner) { | ||
joiner.cb(result, isErr); | ||
}); | ||
task$$1.joiners = null; | ||
} | ||
function setContext(props) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
check(props, object, createSetContextWarning('task', props)); | ||
} | ||
assignWithSymbols(context, props); | ||
} | ||
function toPromise() { | ||
if (deferredEnd) { | ||
return deferredEnd.promise; | ||
} | ||
deferredEnd = deferred(); | ||
if (status === ABORTED) { | ||
deferredEnd.reject(taskError); | ||
} else if (status !== RUNNING) { | ||
deferredEnd.resolve(taskResult); | ||
} | ||
return deferredEnd.promise; | ||
} | ||
var task$$1 = (_task = {}, _task[TASK] = true, _task.id = parentEffectId, _task.meta = meta, _task.isRoot = isRoot, _task.context = context, _task.joiners = [], _task.queue = queue, _task.cancel = cancel, _task.cont = cont, _task.end = end, _task.setContext = setContext, _task.toPromise = toPromise, _task.isRunning = function isRunning() { | ||
return status === RUNNING; | ||
}, _task.isCancelled = function isCancelled() { | ||
return status === CANCELLED$1 || status === RUNNING && mainTask.status === CANCELLED$1; | ||
}, _task.isAborted = function isAborted() { | ||
return status === ABORTED; | ||
}, _task.result = function result() { | ||
return taskResult; | ||
}, _task.error = function error() { | ||
return taskError; | ||
}, _task); | ||
return task$$1; | ||
} | ||
function proc(env, iterator$$1, parentContext, parentEffectId, meta, cont) { | ||
function proc(env, iterator$$1, parentContext, parentEffectId, meta, isRoot, cont) { | ||
if (process.env.NODE_ENV !== 'production' && iterator$$1[asyncIteratorSymbol]) { | ||
@@ -612,6 +1061,3 @@ throw new Error("redux-saga doesn't support async generators, please use only regular ones"); | ||
var taskContext = Object.create(parentContext); | ||
var finalRunEffect = env.finalizeRunEffect(runEffect); | ||
var crashedEffect = null; | ||
var cancelledDueToErrorTasks = []; | ||
/** | ||
@@ -624,24 +1070,27 @@ Tracks the current effect cancellation | ||
next.cancel = noop; | ||
/** | ||
Creates a new task descriptor for this generator, We'll also create a main task | ||
to track the main flow (besides other forked tasks) | ||
**/ | ||
/** Creates a main task to track the main flow */ | ||
var task$$1 = newTask(parentEffectId, meta, cont); | ||
var mainTask = { | ||
meta: meta, | ||
cancel: cancelMain, | ||
_isRunning: true, | ||
_isCancelled: false | ||
status: RUNNING | ||
/** | ||
Creates a new task descriptor for this generator. | ||
A task is the aggregation of it's mainTask and all it's forked tasks. | ||
**/ | ||
}; | ||
var taskQueue = forkQueue(mainTask, function onAbort() { | ||
cancelledDueToErrorTasks.push.apply(cancelledDueToErrorTasks, taskQueue.getTaskNames()); | ||
}, end); | ||
/** | ||
cancellation of the main task. We'll simply resume the Generator with a Cancel | ||
**/ | ||
var task$$1 = newTask(env, mainTask, parentContext, parentEffectId, meta, isRoot, cont); | ||
var executingContext = { | ||
task: task$$1, | ||
digestEffect: digestEffect | ||
/** | ||
cancellation of the main task. We'll simply resume the Generator with a TASK_CANCEL | ||
**/ | ||
}; | ||
function cancelMain() { | ||
if (mainTask._isRunning && !mainTask._isCancelled) { | ||
mainTask._isCancelled = true; | ||
if (mainTask.status === RUNNING) { | ||
mainTask.status = CANCELLED$1; | ||
next(TASK_CANCEL); | ||
@@ -651,26 +1100,2 @@ } | ||
/** | ||
This may be called by a parent generator to trigger/propagate cancellation | ||
cancel all pending tasks (including the main task), then end the current task. | ||
Cancellation propagates down to the whole execution tree holded by this Parent task | ||
It's also propagated to all joiners of this task and their execution tree/joiners | ||
Cancellation is noop for terminated/Cancelled tasks tasks | ||
**/ | ||
function cancel() { | ||
/** | ||
We need to check both Running and Cancelled status | ||
Tasks can be Cancelled but still Running | ||
**/ | ||
if (task$$1._isRunning && !task$$1._isCancelled) { | ||
task$$1._isCancelled = true; | ||
taskQueue.cancelAll(); | ||
/** | ||
Ending with a Never result will propagate the Cancellation to all joiners | ||
**/ | ||
end(TASK_CANCEL); | ||
} | ||
} | ||
/** | ||
attaches cancellation logic to this task's continuation | ||
@@ -681,3 +1106,3 @@ this will permit cancellation to propagate down the call chain | ||
cont && (cont.cancel = cancel); // kicks up the generator | ||
cont.cancel = task$$1.cancel; // kicks up the generator | ||
@@ -688,13 +1113,12 @@ next(); // then return the task descriptor to the caller | ||
/** | ||
This is the generator driver | ||
It's a recursive async/continuation function which calls itself | ||
until the generator terminates or throws | ||
**/ | ||
* This is the generator driver | ||
* It's a recursive async/continuation function which calls itself | ||
* until the generator terminates or throws | ||
* @param {internal commands(TASK_CANCEL | TERMINATE) | any} arg - value, generator will be resumed with. | ||
* @param {boolean} isErr - the flag shows if effect finished with an error | ||
* | ||
* receives either (command | effect result, false) or (any thrown thing, true) | ||
*/ | ||
function next(arg, isErr) { | ||
// Preventive measure. If we end up here, then there is really something wrong | ||
if (!mainTask._isRunning) { | ||
throw new Error('Trying to resume an already finished generator'); | ||
} | ||
try { | ||
@@ -704,3 +1128,5 @@ var result; | ||
if (isErr) { | ||
result = iterator$$1.throw(arg); | ||
result = iterator$$1.throw(arg); // user handled the error, we can clear bookkept values | ||
clear(); | ||
} else if (shouldCancel(arg)) { | ||
@@ -713,3 +1139,3 @@ /** | ||
**/ | ||
mainTask._isCancelled = true; | ||
mainTask.status = CANCELLED$1; | ||
/** | ||
@@ -739,3 +1165,3 @@ Cancels the current effect; this will propagate the cancellation down to any called tasks | ||
if (!result.done) { | ||
digestEffect(result.value, parentEffectId, '', next); | ||
digestEffect(result.value, parentEffectId, next); | ||
} else { | ||
@@ -745,11 +1171,14 @@ /** | ||
**/ | ||
mainTask._isRunning = false; | ||
if (mainTask.status !== CANCELLED$1) { | ||
mainTask.status = DONE; | ||
} | ||
mainTask.cont(result.value); | ||
} | ||
} catch (error) { | ||
if (mainTask._isCancelled) { | ||
env.logError(error); | ||
if (mainTask.status === CANCELLED$1) { | ||
throw error; | ||
} | ||
mainTask._isRunning = false; | ||
mainTask.status = ABORTED; | ||
mainTask.cont(error, true); | ||
@@ -759,40 +1188,2 @@ } | ||
function end(result, isErr) { | ||
task$$1._isRunning = false; | ||
if (!isErr) { | ||
task$$1._result = result; | ||
task$$1._deferredEnd && task$$1._deferredEnd.resolve(result); | ||
} else { | ||
addSagaStack(result, { | ||
meta: meta, | ||
effect: crashedEffect, | ||
cancelledTasks: cancelledDueToErrorTasks | ||
}); | ||
if (!task$$1.cont) { | ||
if (result && result.sagaStack) { | ||
result.sagaStack = sagaStackToString(result.sagaStack); | ||
} | ||
if (env.onError) { | ||
env.onError(result); | ||
} else { | ||
// TODO: could we skip this when _deferredEnd is attached? | ||
env.logError(result); | ||
} | ||
} | ||
task$$1._error = result; | ||
task$$1._isAborted = true; | ||
task$$1._deferredEnd && task$$1._deferredEnd.reject(result); | ||
} | ||
task$$1.cont && task$$1.cont(result, isErr); | ||
task$$1.joiners.forEach(function (j) { | ||
return j.cb(result, isErr); | ||
}); | ||
task$$1.joiners = null; | ||
} | ||
function runEffect(effect, effectId, currCb) { | ||
@@ -814,7 +1205,9 @@ /** | ||
} else if (iterator(effect)) { | ||
resolveIterator(effect, effectId, meta, currCb); | ||
// resolve iterator | ||
proc(env, effect, task$$1.context, effectId, meta, | ||
/* isRoot */ | ||
false, currCb); | ||
} else if (effect && effect[IO]) { | ||
var type = effect.type, | ||
payload = effect.payload; | ||
if (type === TAKE) runTakeEffect(payload, currCb);else if (type === PUT) runPutEffect(payload, currCb);else if (type === ALL) runAllEffect(payload, effectId, currCb);else if (type === RACE) runRaceEffect(payload, effectId, currCb);else if (type === CALL) runCallEffect(payload, effectId, currCb);else if (type === CPS) runCPSEffect(payload, currCb);else if (type === FORK) runForkEffect(payload, effectId, currCb);else if (type === JOIN) runJoinEffect(payload, currCb);else if (type === CANCEL$1) runCancelEffect(payload, currCb);else if (type === SELECT) runSelectEffect(payload, currCb);else if (type === ACTION_CHANNEL) runChannelEffect(payload, currCb);else if (type === FLUSH) runFlushEffect(payload, currCb);else if (type === CANCELLED) runCancelledEffect(payload, currCb);else if (type === GET_CONTEXT) runGetContextEffect(payload, currCb);else if (type === SET_CONTEXT) runSetContextEffect(payload, currCb);else currCb(effect); | ||
var effectRunner = effectRunnerMap[effect.type]; | ||
effectRunner(env, effect.payload, currCb, executingContext); | ||
} else { | ||
@@ -826,3 +1219,3 @@ // anything else returned as is | ||
function digestEffect(effect, parentEffectId, label, cb) { | ||
function digestEffect(effect, parentEffectId, cb, label) { | ||
if (label === void 0) { | ||
@@ -832,3 +1225,3 @@ label = ''; | ||
var effectId = uid(); | ||
var effectId = nextEffectId(); | ||
env.sagaMonitor && env.sagaMonitor.effectTriggered({ | ||
@@ -865,3 +1258,3 @@ effectId: effectId, | ||
if (isErr) { | ||
crashedEffect = effect; | ||
setCrashedEffect(effect); | ||
} | ||
@@ -882,14 +1275,4 @@ | ||
effectSettled = true; | ||
/** | ||
propagates cancel downward | ||
catch uncaught cancellations errors; since we can no longer call the completion | ||
callback, log errors raised during cancellations into the console | ||
**/ | ||
currCb.cancel(); // propagates cancel downward | ||
try { | ||
currCb.cancel(); | ||
} catch (err) { | ||
env.logError(err); | ||
} | ||
currCb.cancel = noop; // defensive measure | ||
@@ -902,378 +1285,2 @@ | ||
} | ||
function resolvePromise(promise$$1, cb) { | ||
var cancelPromise = promise$$1[CANCEL]; | ||
if (func(cancelPromise)) { | ||
cb.cancel = cancelPromise; | ||
} else if (func(promise$$1.abort)) { | ||
cb.cancel = function () { | ||
return promise$$1.abort(); | ||
}; | ||
} | ||
promise$$1.then(cb, function (error) { | ||
return cb(error, true); | ||
}); | ||
} | ||
function resolveIterator(iterator$$1, effectId, meta, cb) { | ||
proc(env, iterator$$1, taskContext, effectId, meta, cb); | ||
} | ||
function runTakeEffect(_ref2, cb) { | ||
var _ref2$channel = _ref2.channel, | ||
channel$$1 = _ref2$channel === void 0 ? env.stdChannel : _ref2$channel, | ||
pattern$$1 = _ref2.pattern, | ||
maybe = _ref2.maybe; | ||
var takeCb = function takeCb(input) { | ||
if (input instanceof Error) { | ||
cb(input, true); | ||
return; | ||
} | ||
if (isEnd(input) && !maybe) { | ||
cb(TERMINATE); | ||
return; | ||
} | ||
cb(input); | ||
}; | ||
try { | ||
channel$$1.take(takeCb, notUndef(pattern$$1) ? matcher(pattern$$1) : null); | ||
} catch (err) { | ||
cb(err, true); | ||
return; | ||
} | ||
cb.cancel = takeCb.cancel; | ||
} | ||
function runPutEffect(_ref3, cb) { | ||
var channel$$1 = _ref3.channel, | ||
action = _ref3.action, | ||
resolve = _ref3.resolve; | ||
/** | ||
Schedule the put in case another saga is holding a lock. | ||
The put will be executed atomically. ie nested puts will execute after | ||
this put has terminated. | ||
**/ | ||
asap(function () { | ||
var result; | ||
try { | ||
result = (channel$$1 ? channel$$1.put : env.dispatch)(action); | ||
} catch (error) { | ||
cb(error, true); | ||
return; | ||
} | ||
if (resolve && promise(result)) { | ||
resolvePromise(result, cb); | ||
} else { | ||
cb(result); | ||
} | ||
}); // Put effects are non cancellables | ||
} | ||
function runCallEffect(_ref4, effectId, cb) { | ||
var context = _ref4.context, | ||
fn = _ref4.fn, | ||
args = _ref4.args; | ||
// catch synchronous failures; see #152 | ||
try { | ||
var result = fn.apply(context, args); | ||
if (promise(result)) { | ||
resolvePromise(result, cb); | ||
return; | ||
} | ||
if (iterator(result)) { | ||
resolveIterator(result, effectId, getMetaInfo(fn), cb); | ||
return; | ||
} | ||
cb(result); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runCPSEffect(_ref5, cb) { | ||
var context = _ref5.context, | ||
fn = _ref5.fn, | ||
args = _ref5.args; | ||
// CPS (ie node style functions) can define their own cancellation logic | ||
// by setting cancel field on the cb | ||
// catch synchronous failures; see #152 | ||
try { | ||
var cpsCb = function cpsCb(err, res) { | ||
return undef(err) ? cb(res) : cb(err, true); | ||
}; | ||
fn.apply(context, args.concat(cpsCb)); | ||
if (cpsCb.cancel) { | ||
cb.cancel = function () { | ||
return cpsCb.cancel(); | ||
}; | ||
} | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runForkEffect(_ref6, effectId, cb) { | ||
var context = _ref6.context, | ||
fn = _ref6.fn, | ||
args = _ref6.args, | ||
detached = _ref6.detached; | ||
var taskIterator = createTaskIterator({ | ||
context: context, | ||
fn: fn, | ||
args: args | ||
}); | ||
var meta = getIteratorMetaInfo(taskIterator, fn); | ||
try { | ||
suspend(); | ||
var _task = proc(env, taskIterator, taskContext, effectId, meta, detached ? null : noop); | ||
if (detached) { | ||
cb(_task); | ||
} else { | ||
if (_task._isRunning) { | ||
taskQueue.addTask(_task); | ||
cb(_task); | ||
} else if (_task._error) { | ||
taskQueue.abort(_task._error); | ||
} else { | ||
cb(_task); | ||
} | ||
} | ||
} finally { | ||
flush(); | ||
} // Fork effects are non cancellables | ||
} | ||
function runJoinEffect(taskOrTasks, cb) { | ||
if (array(taskOrTasks)) { | ||
if (taskOrTasks.length === 0) { | ||
cb([]); | ||
return; | ||
} | ||
var childCallbacks = createAllStyleChildCallbacks(taskOrTasks, cb); | ||
taskOrTasks.forEach(function (t, i) { | ||
joinSingleTask(t, childCallbacks[i]); | ||
}); | ||
} else { | ||
joinSingleTask(taskOrTasks, cb); | ||
} | ||
} | ||
function joinSingleTask(taskToJoin, cb) { | ||
if (taskToJoin.isRunning()) { | ||
var joiner = { | ||
task: task$$1, | ||
cb: cb | ||
}; | ||
cb.cancel = function () { | ||
return remove(taskToJoin.joiners, joiner); | ||
}; | ||
taskToJoin.joiners.push(joiner); | ||
} else { | ||
if (taskToJoin.isAborted()) { | ||
cb(taskToJoin.error(), true); | ||
} else { | ||
cb(taskToJoin.result()); | ||
} | ||
} | ||
} | ||
function runCancelEffect(taskOrTasks, cb) { | ||
if (taskOrTasks === SELF_CANCELLATION) { | ||
cancelSingleTask(task$$1); | ||
} else if (array(taskOrTasks)) { | ||
taskOrTasks.forEach(cancelSingleTask); | ||
} else { | ||
cancelSingleTask(taskOrTasks); | ||
} | ||
cb(); // cancel effects are non cancellables | ||
} | ||
function cancelSingleTask(taskToCancel) { | ||
if (taskToCancel.isRunning()) { | ||
taskToCancel.cancel(); | ||
} | ||
} | ||
function runAllEffect(effects, effectId, cb) { | ||
var keys = Object.keys(effects); | ||
if (keys.length === 0) { | ||
cb(array(effects) ? [] : {}); | ||
return; | ||
} | ||
var childCallbacks = createAllStyleChildCallbacks(effects, cb); | ||
keys.forEach(function (key) { | ||
return digestEffect(effects[key], effectId, key, childCallbacks[key]); | ||
}); | ||
} | ||
function runRaceEffect(effects, effectId, cb) { | ||
var completed; | ||
var keys = Object.keys(effects); | ||
var childCbs = {}; | ||
keys.forEach(function (key) { | ||
var chCbAtKey = function chCbAtKey(res, isErr) { | ||
if (completed) { | ||
return; | ||
} | ||
if (isErr || shouldComplete(res)) { | ||
// Race Auto cancellation | ||
cb.cancel(); | ||
cb(res, isErr); | ||
} else { | ||
var _response; | ||
cb.cancel(); | ||
completed = true; | ||
var response = (_response = {}, _response[key] = res, _response); | ||
cb(array(effects) ? array$1.from(_extends({}, response, { | ||
length: keys.length | ||
})) : response); | ||
} | ||
}; | ||
chCbAtKey.cancel = noop; | ||
childCbs[key] = chCbAtKey; | ||
}); | ||
cb.cancel = function () { | ||
// prevents unnecessary cancellation | ||
if (!completed) { | ||
completed = true; | ||
keys.forEach(function (key) { | ||
return childCbs[key].cancel(); | ||
}); | ||
} | ||
}; | ||
keys.forEach(function (key) { | ||
if (completed) { | ||
return; | ||
} | ||
digestEffect(effects[key], effectId, key, childCbs[key]); | ||
}); | ||
} | ||
function runSelectEffect(_ref7, cb) { | ||
var selector = _ref7.selector, | ||
args = _ref7.args; | ||
try { | ||
var state = selector.apply(void 0, [env.getState()].concat(args)); | ||
cb(state); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runChannelEffect(_ref8, cb) { | ||
var pattern$$1 = _ref8.pattern, | ||
buffer$$1 = _ref8.buffer; | ||
// TODO: rethink how END is handled | ||
var chan = channel$1(buffer$$1); | ||
var match = matcher(pattern$$1); | ||
var taker = function taker(action) { | ||
if (!isEnd(action)) { | ||
env.stdChannel.take(taker, match); | ||
} | ||
chan.put(action); | ||
}; | ||
var close = chan.close; | ||
chan.close = function () { | ||
taker.cancel(); | ||
close(); | ||
}; | ||
env.stdChannel.take(taker, match); | ||
cb(chan); | ||
} | ||
function runCancelledEffect(data, cb) { | ||
cb(Boolean(mainTask._isCancelled)); | ||
} | ||
function runFlushEffect(channel$$1, cb) { | ||
channel$$1.flush(cb); | ||
} | ||
function runGetContextEffect(prop, cb) { | ||
cb(taskContext[prop]); | ||
} | ||
function runSetContextEffect(props, cb) { | ||
assignWithSymbols(taskContext, props); | ||
cb(); | ||
} | ||
function newTask(id, meta, cont) { | ||
var _task2; | ||
var task$$1 = (_task2 = {}, _task2[TASK] = true, _task2.id = id, _task2.meta = meta, _task2._deferredEnd = null, _task2.toPromise = function toPromise() { | ||
if (task$$1._deferredEnd) { | ||
return task$$1._deferredEnd.promise; | ||
} | ||
var def = deferred(); | ||
task$$1._deferredEnd = def; | ||
if (!task$$1._isRunning) { | ||
if (task$$1._isAborted) { | ||
def.reject(task$$1._error); | ||
} else { | ||
def.resolve(task$$1._result); | ||
} | ||
} | ||
return def.promise; | ||
}, _task2.cont = cont, _task2.joiners = [], _task2.cancel = cancel, _task2._isRunning = true, _task2._isCancelled = false, _task2._isAborted = false, _task2._result = undefined, _task2._error = undefined, _task2.isRunning = function isRunning() { | ||
return task$$1._isRunning; | ||
}, _task2.isCancelled = function isCancelled() { | ||
return task$$1._isCancelled; | ||
}, _task2.isAborted = function isAborted() { | ||
return task$$1._isAborted; | ||
}, _task2.result = function result() { | ||
return task$$1._result; | ||
}, _task2.error = function error() { | ||
return task$$1._error; | ||
}, _task2.setContext = function setContext(props) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
check(props, object, createSetContextWarning('task', props)); | ||
} | ||
assignWithSymbols(taskContext, props); | ||
}, _task2); | ||
return task$$1; | ||
} | ||
} | ||
@@ -1283,3 +1290,14 @@ | ||
var NON_GENERATOR_ERR = RUN_SAGA_SIGNATURE + ": saga argument must be a Generator function!"; | ||
function runSaga(options, saga) { | ||
function runSaga(_ref, saga) { | ||
var _ref$channel = _ref.channel, | ||
channel$$1 = _ref$channel === void 0 ? stdChannel() : _ref$channel, | ||
dispatch = _ref.dispatch, | ||
getState = _ref.getState, | ||
_ref$context = _ref.context, | ||
context = _ref$context === void 0 ? {} : _ref$context, | ||
sagaMonitor = _ref.sagaMonitor, | ||
effectMiddlewares = _ref.effectMiddlewares, | ||
_ref$onError = _ref.onError, | ||
onError = _ref$onError === void 0 ? logError : _ref$onError; | ||
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { | ||
@@ -1299,13 +1317,3 @@ args[_key - 2] = arguments[_key]; | ||
var _options$channel = options.channel, | ||
channel$$1 = _options$channel === void 0 ? stdChannel() : _options$channel, | ||
dispatch = options.dispatch, | ||
getState = options.getState, | ||
_options$context = options.context, | ||
context = _options$context === void 0 ? {} : _options$context, | ||
sagaMonitor = options.sagaMonitor, | ||
logger = options.logger, | ||
effectMiddlewares = options.effectMiddlewares, | ||
onError = options.onError; | ||
var effectId = uid(); | ||
var effectId = nextEffectId(); | ||
@@ -1327,31 +1335,29 @@ if (sagaMonitor) { | ||
if (process.env.NODE_ENV !== 'production' && notUndef(effectMiddlewares)) { | ||
var MIDDLEWARE_TYPE_ERROR = 'effectMiddlewares must be an array of functions'; | ||
check(effectMiddlewares, array, MIDDLEWARE_TYPE_ERROR); | ||
effectMiddlewares.forEach(function (effectMiddleware) { | ||
return check(effectMiddleware, func, MIDDLEWARE_TYPE_ERROR); | ||
}); | ||
} | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (notUndef(onError)) { | ||
check(onError, func, 'onError must be a function'); | ||
if (notUndef(dispatch)) { | ||
check(dispatch, func, 'dispatch must be a function'); | ||
} | ||
} | ||
var log$$1 = logger || log; | ||
if (notUndef(getState)) { | ||
check(getState, func, 'getState must be a function'); | ||
} | ||
var logError = function logError(err) { | ||
log$$1('error', err); | ||
if (err && err.sagaStack) { | ||
log$$1('error', err.sagaStack); | ||
if (notUndef(effectMiddlewares)) { | ||
var MIDDLEWARE_TYPE_ERROR = 'effectMiddlewares must be an array of functions'; | ||
check(effectMiddlewares, array, MIDDLEWARE_TYPE_ERROR); | ||
effectMiddlewares.forEach(function (effectMiddleware) { | ||
return check(effectMiddleware, func, MIDDLEWARE_TYPE_ERROR); | ||
}); | ||
} | ||
}; | ||
var middleware = effectMiddlewares && compose.apply(void 0, effectMiddlewares); | ||
check(onError, func, 'onError passed to the redux-saga is not a function!'); | ||
} | ||
var finalizeRunEffect = function finalizeRunEffect(runEffect) { | ||
if (func(middleware)) { | ||
return function finalRunEffect(effect, effectId, currCb) { | ||
var finalizeRunEffect; | ||
if (effectMiddlewares) { | ||
var middleware = compose.apply(void 0, effectMiddlewares); | ||
finalizeRunEffect = function finalizeRunEffect(runEffect) { | ||
return function (effect, effectId, currCb) { | ||
var plainRunEffect = function plainRunEffect(eff) { | ||
@@ -1363,21 +1369,20 @@ return runEffect(eff, effectId, currCb); | ||
}; | ||
} else { | ||
return runEffect; | ||
} | ||
}; | ||
}; | ||
} else { | ||
finalizeRunEffect = identity; | ||
} | ||
var env = { | ||
stdChannel: channel$$1, | ||
channel: channel$$1, | ||
dispatch: wrapSagaDispatch(dispatch), | ||
getState: getState, | ||
sagaMonitor: sagaMonitor, | ||
logError: logError, | ||
onError: onError, | ||
finalizeRunEffect: finalizeRunEffect | ||
}; | ||
return immediately(function () { | ||
var task$$1 = proc(env, iterator$$1, context, effectId, getMetaInfo(saga), | ||
/* isRoot */ | ||
true, noop); | ||
try { | ||
suspend(); | ||
var task$$1 = proc(env, iterator$$1, context, effectId, getMetaInfo(saga), null); | ||
if (sagaMonitor) { | ||
@@ -1388,5 +1393,3 @@ sagaMonitor.effectResolved(effectId, task$$1); | ||
return task$$1; | ||
} finally { | ||
flush(); | ||
} | ||
}); | ||
} | ||
@@ -1402,22 +1405,11 @@ | ||
context = _ref2$context === void 0 ? {} : _ref2$context, | ||
options = _objectWithoutPropertiesLoose(_ref2, ["context"]); | ||
_ref2$channel = _ref2.channel, | ||
channel$$1 = _ref2$channel === void 0 ? stdChannel() : _ref2$channel, | ||
sagaMonitor = _ref2.sagaMonitor, | ||
options = _objectWithoutPropertiesLoose(_ref2, ["context", "channel", "sagaMonitor"]); | ||
var sagaMonitor = options.sagaMonitor, | ||
logger = options.logger, | ||
onError = options.onError, | ||
effectMiddlewares = options.effectMiddlewares; | ||
var boundRunSaga; | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (notUndef(logger)) { | ||
check(logger, func, 'options.logger passed to the Saga middleware is not a function!'); | ||
} | ||
if (notUndef(onError)) { | ||
check(onError, func, 'options.onError passed to the Saga middleware is not a function!'); | ||
} | ||
if (notUndef(options.emitter)) { | ||
check(options.emitter, func, 'options.emitter passed to the Saga middleware is not a function!'); | ||
} | ||
check(channel$$1, channel, 'options.channel passed to the Saga middleware is not a channel'); | ||
} | ||
@@ -1428,5 +1420,3 @@ | ||
dispatch = _ref3.dispatch; | ||
var channel$$1 = stdChannel(); | ||
channel$$1.put = (options.emitter || identity)(channel$$1.put); | ||
boundRunSaga = runSaga.bind(null, { | ||
boundRunSaga = runSaga.bind(null, _extends({}, options, { | ||
context: context, | ||
@@ -1436,7 +1426,4 @@ channel: channel$$1, | ||
getState: getState, | ||
sagaMonitor: sagaMonitor, | ||
logger: logger, | ||
onError: onError, | ||
effectMiddlewares: effectMiddlewares | ||
}); | ||
sagaMonitor: sagaMonitor | ||
})); | ||
return function (next) { | ||
@@ -1443,0 +1430,0 @@ return function (action) { |
@@ -8,8 +8,7 @@ 'use strict'; | ||
var is = require('@redux-saga/is'); | ||
var __chunk_1 = require('./chunk-795916d1.js'); | ||
var __chunk_1 = require('./chunk-0077808e.js'); | ||
var symbols = require('@redux-saga/symbols'); | ||
var __chunk_2 = require('./chunk-51a22d4b.js'); | ||
var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); | ||
var deferred = _interopDefault(require('@redux-saga/deferred')); | ||
var redux = require('redux'); | ||
var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); | ||
var _objectWithoutPropertiesLoose = _interopDefault(require('@babel/runtime/helpers/objectWithoutPropertiesLoose')); | ||
@@ -56,2 +55,14 @@ require('@redux-saga/delay-p'); | ||
/** | ||
* Puts the scheduler in a `suspended` state and executes a task immediately. | ||
*/ | ||
function immediately(task) { | ||
try { | ||
suspend(); | ||
return task(); | ||
} finally { | ||
flush(); | ||
} | ||
} | ||
/** | ||
Puts the scheduler in a `suspended` state. Scheduled tasks will be queued until the | ||
@@ -68,2 +79,3 @@ scheduler is released. | ||
function release() { | ||
@@ -130,3 +142,3 @@ semaphore--; | ||
if (buffer === void 0) { | ||
buffer = __chunk_2.expanding(); | ||
buffer = __chunk_1.expanding(); | ||
} | ||
@@ -166,3 +178,3 @@ | ||
function flush$$1(cb) { | ||
function flush(cb) { | ||
@@ -196,3 +208,3 @@ if (closed && buffer.isEmpty()) { | ||
put: put, | ||
flush: flush$$1, | ||
flush: flush, | ||
close: close | ||
@@ -203,3 +215,3 @@ }; | ||
if (buffer === void 0) { | ||
buffer = __chunk_2.none(); | ||
buffer = __chunk_1.none(); | ||
} | ||
@@ -329,127 +341,416 @@ | ||
function formatLocation(fileName, lineNumber) { | ||
return fileName + "?" + lineNumber; | ||
var RUNNING = 0; | ||
var CANCELLED = 1; | ||
var ABORTED = 2; | ||
var DONE = 3; | ||
function resolvePromise(promise, cb) { | ||
var cancelPromise = promise[symbols.CANCEL]; | ||
if (is.func(cancelPromise)) { | ||
cb.cancel = cancelPromise; | ||
} | ||
promise.then(cb, function (error) { | ||
cb(error, true); | ||
}); | ||
} | ||
function getLocation(instrumented) { | ||
return instrumented[symbols.SAGA_LOCATION]; | ||
var current = 0; | ||
var nextEffectId = (function () { | ||
return ++current; | ||
}); | ||
var _effectRunnerMap; | ||
function getIteratorMetaInfo(iterator, fn) { | ||
if (iterator.isSagaIterator) { | ||
return { | ||
name: iterator.meta.name | ||
}; | ||
} | ||
return __chunk_1.getMetaInfo(fn); | ||
} | ||
function effectLocationAsString(effect) { | ||
var location = getLocation(effect); | ||
function createTaskIterator(_ref) { | ||
var context = _ref.context, | ||
fn = _ref.fn, | ||
args = _ref.args; | ||
if (location) { | ||
var code = location.code, | ||
fileName = location.fileName, | ||
lineNumber = location.lineNumber; | ||
var source = code + " " + formatLocation(fileName, lineNumber); | ||
return source; | ||
// catch synchronous failures; see #152 and #441 | ||
try { | ||
var result = fn.apply(context, args); // i.e. a generator function returns an iterator | ||
if (is.iterator(result)) { | ||
return result; | ||
} | ||
var next = function next(value) { | ||
if (value === void 0) { | ||
value = result; | ||
} | ||
return { | ||
value: value, | ||
done: !is.promise(value) | ||
}; | ||
}; | ||
return __chunk_1.makeIterator(next); | ||
} catch (err) { | ||
// do not bubble up synchronous failures for detached forks | ||
// instead create a failed task. See #152 and #441 | ||
return __chunk_1.makeIterator(function () { | ||
throw err; | ||
}); | ||
} | ||
} | ||
return ''; | ||
function runPutEffect(env, _ref2, cb) { | ||
var channel$$1 = _ref2.channel, | ||
action = _ref2.action, | ||
resolve = _ref2.resolve; | ||
/** | ||
Schedule the put in case another saga is holding a lock. | ||
The put will be executed atomically. ie nested puts will execute after | ||
this put has terminated. | ||
**/ | ||
asap(function () { | ||
var result; | ||
try { | ||
result = (channel$$1 ? channel$$1.put : env.dispatch)(action); | ||
} catch (error) { | ||
cb(error, true); | ||
return; | ||
} | ||
if (resolve && is.promise(result)) { | ||
resolvePromise(result, cb); | ||
} else { | ||
cb(result); | ||
} | ||
}); // Put effects are non cancellables | ||
} | ||
function sagaLocationAsString(sagaMeta) { | ||
var name = sagaMeta.name, | ||
location = sagaMeta.location; | ||
function runTakeEffect(env, _ref3, cb) { | ||
var _ref3$channel = _ref3.channel, | ||
channel$$1 = _ref3$channel === void 0 ? env.channel : _ref3$channel, | ||
pattern = _ref3.pattern, | ||
maybe = _ref3.maybe; | ||
if (location) { | ||
return name + " " + formatLocation(location.fileName, location.lineNumber); | ||
var takeCb = function takeCb(input) { | ||
if (input instanceof Error) { | ||
cb(input, true); | ||
return; | ||
} | ||
if (isEnd(input) && !maybe) { | ||
cb(symbols.TERMINATE); | ||
return; | ||
} | ||
cb(input); | ||
}; | ||
try { | ||
channel$$1.take(takeCb, is.notUndef(pattern) ? matcher(pattern) : null); | ||
} catch (err) { | ||
cb(err, true); | ||
return; | ||
} | ||
return name; | ||
cb.cancel = takeCb.cancel; | ||
} | ||
var flatMap = function flatMap(mapper, arr) { | ||
var _ref; | ||
function runCallEffect(env, _ref4, cb, _ref5) { | ||
var context = _ref4.context, | ||
fn = _ref4.fn, | ||
args = _ref4.args; | ||
var task = _ref5.task; | ||
return (_ref = []).concat.apply(_ref, arr.map(mapper)); | ||
}; | ||
// catch synchronous failures; see #152 | ||
try { | ||
var result = fn.apply(context, args); | ||
function cancelledTasksAsString(sagaStack) { | ||
var cancelledTasks = flatMap(function (i) { | ||
return i.cancelledTasks; | ||
}, sagaStack); | ||
if (is.promise(result)) { | ||
resolvePromise(result, cb); | ||
return; | ||
} | ||
if (!cancelledTasks.length) { | ||
return ''; | ||
if (is.iterator(result)) { | ||
// resolve iterator | ||
proc(env, result, task.context, current, __chunk_1.getMetaInfo(fn), | ||
/* isRoot */ | ||
false, cb); | ||
return; | ||
} | ||
cb(result); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
return ['Tasks cancelled due to error:'].concat(cancelledTasks).join('\n'); | ||
function runCPSEffect(env, _ref6, cb) { | ||
var context = _ref6.context, | ||
fn = _ref6.fn, | ||
args = _ref6.args; | ||
// CPS (ie node style functions) can define their own cancellation logic | ||
// by setting cancel field on the cb | ||
// catch synchronous failures; see #152 | ||
try { | ||
var cpsCb = function cpsCb(err, res) { | ||
if (is.undef(err)) { | ||
cb(res); | ||
} else { | ||
cb(err, true); | ||
} | ||
}; | ||
fn.apply(context, args.concat(cpsCb)); | ||
if (cpsCb.cancel) { | ||
cb.cancel = cpsCb.cancel; | ||
} | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
/** | ||
@param {saga, effect}[] sagaStack | ||
@returns {string} | ||
@example | ||
The above error occurred in task errorInPutSaga {pathToFile} | ||
when executing effect put({type: 'REDUCER_ACTION_ERROR_IN_PUT'}) {pathToFile} | ||
created by fetchSaga {pathToFile} | ||
created by rootSaga {pathToFile} | ||
*/ | ||
function runForkEffect(env, _ref7, cb, _ref8) { | ||
var context = _ref7.context, | ||
fn = _ref7.fn, | ||
args = _ref7.args, | ||
detached = _ref7.detached; | ||
var parent = _ref8.task; | ||
var taskIterator = createTaskIterator({ | ||
context: context, | ||
fn: fn, | ||
args: args | ||
}); | ||
var meta = getIteratorMetaInfo(taskIterator, fn); | ||
immediately(function () { | ||
var child = proc(env, taskIterator, parent.context, current, meta, detached, __chunk_1.noop); | ||
if (detached) { | ||
cb(child); | ||
} else { | ||
if (child.isRunning()) { | ||
parent.queue.addTask(child); | ||
cb(child); | ||
} else if (child.isAborted()) { | ||
parent.queue.abort(child.error()); | ||
} else { | ||
cb(child); | ||
} | ||
} | ||
}); // Fork effects are non cancellables | ||
} | ||
function sagaStackToString(sagaStack) { | ||
var firstSaga = sagaStack[0], | ||
otherSagas = sagaStack.slice(1); | ||
var crashedEffectLocation = firstSaga.effect ? effectLocationAsString(firstSaga.effect) : null; | ||
var errorMessage = "The above error occurred in task " + sagaLocationAsString(firstSaga.meta) + (crashedEffectLocation ? " \n when executing effect " + crashedEffectLocation : ''); | ||
return [errorMessage].concat(otherSagas.map(function (s) { | ||
return " created by " + sagaLocationAsString(s.meta); | ||
}), [cancelledTasksAsString(sagaStack)]).join('\n'); | ||
function runJoinEffect(env, taskOrTasks, cb, _ref9) { | ||
var task = _ref9.task; | ||
var joinSingleTask = function joinSingleTask(taskToJoin, cb) { | ||
if (taskToJoin.isRunning()) { | ||
var joiner = { | ||
task: task, | ||
cb: cb | ||
}; | ||
cb.cancel = function () { | ||
__chunk_1.remove(taskToJoin.joiners, joiner); | ||
}; | ||
taskToJoin.joiners.push(joiner); | ||
} else { | ||
if (taskToJoin.isAborted()) { | ||
cb(taskToJoin.error(), true); | ||
} else { | ||
cb(taskToJoin.result()); | ||
} | ||
} | ||
}; | ||
if (is.array(taskOrTasks)) { | ||
if (taskOrTasks.length === 0) { | ||
cb([]); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(taskOrTasks, cb); | ||
taskOrTasks.forEach(function (t, i) { | ||
joinSingleTask(t, childCallbacks[i]); | ||
}); | ||
} else { | ||
joinSingleTask(taskOrTasks, cb); | ||
} | ||
} | ||
function addSagaStack(errorObject, errorStack) { | ||
if (typeof errorObject === 'object') { | ||
if (typeof errorObject.sagaStack === 'undefined') { | ||
// property is used as a stack of descriptors for failed sagas | ||
// after formatting to string it will be re-written | ||
// to pass sagaStack as a string in user land | ||
Object.defineProperty(errorObject, 'sagaStack', { | ||
value: [], | ||
writable: true, | ||
enumerable: false | ||
function cancelSingleTask(taskToCancel) { | ||
if (taskToCancel.isRunning()) { | ||
taskToCancel.cancel(); | ||
} | ||
} | ||
function runCancelEffect(env, taskOrTasks, cb, _ref10) { | ||
var task = _ref10.task; | ||
if (taskOrTasks === symbols.SELF_CANCELLATION) { | ||
cancelSingleTask(task); | ||
} else if (is.array(taskOrTasks)) { | ||
taskOrTasks.forEach(cancelSingleTask); | ||
} else { | ||
cancelSingleTask(taskOrTasks); | ||
} | ||
cb(); // cancel effects are non cancellables | ||
} | ||
function runAllEffect(env, effects, cb, _ref11) { | ||
var digestEffect = _ref11.digestEffect; | ||
var effectId = current; | ||
var keys = Object.keys(effects); | ||
if (keys.length === 0) { | ||
cb(is.array(effects) ? [] : {}); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(effects, cb); | ||
keys.forEach(function (key) { | ||
digestEffect(effects[key], effectId, childCallbacks[key], key); | ||
}); | ||
} | ||
function runRaceEffect(env, effects, cb, _ref12) { | ||
var digestEffect = _ref12.digestEffect; | ||
var effectId = current; | ||
var keys = Object.keys(effects); | ||
var response = is.array(effects) ? __chunk_1.createEmptyArray(keys.length) : {}; | ||
var childCbs = {}; | ||
var completed = false; | ||
keys.forEach(function (key) { | ||
var chCbAtKey = function chCbAtKey(res, isErr) { | ||
if (completed) { | ||
return; | ||
} | ||
if (isErr || __chunk_1.shouldComplete(res)) { | ||
// Race Auto cancellation | ||
cb.cancel(); | ||
cb(res, isErr); | ||
} else { | ||
cb.cancel(); | ||
completed = true; | ||
response[key] = res; | ||
cb(response); | ||
} | ||
}; | ||
chCbAtKey.cancel = __chunk_1.noop; | ||
childCbs[key] = chCbAtKey; | ||
}); | ||
cb.cancel = function () { | ||
// prevents unnecessary cancellation | ||
if (!completed) { | ||
completed = true; | ||
keys.forEach(function (key) { | ||
return childCbs[key].cancel(); | ||
}); | ||
} | ||
}; | ||
errorObject.sagaStack.push(errorStack); | ||
keys.forEach(function (key) { | ||
if (completed) { | ||
return; | ||
} | ||
digestEffect(effects[key], effectId, childCbs[key], key); | ||
}); | ||
} | ||
function runSelectEffect(env, _ref13, cb) { | ||
var selector = _ref13.selector, | ||
args = _ref13.args; | ||
try { | ||
var state = selector.apply(void 0, [env.getState()].concat(args)); | ||
cb(state); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function getMetaInfo(fn) { | ||
return { | ||
name: fn.name || 'anonymous', | ||
location: getLocation(fn) | ||
function runChannelEffect(env, _ref14, cb) { | ||
var pattern = _ref14.pattern, | ||
buffer = _ref14.buffer; | ||
var chan = channel(buffer); | ||
var match = matcher(pattern); | ||
var taker = function taker(action) { | ||
if (!isEnd(action)) { | ||
env.channel.take(taker, match); | ||
} | ||
chan.put(action); | ||
}; | ||
var close = chan.close; | ||
chan.close = function () { | ||
taker.cancel(); | ||
close(); | ||
}; | ||
env.channel.take(taker, match); | ||
cb(chan); | ||
} | ||
function getIteratorMetaInfo(iterator, fn) { | ||
if (iterator.isSagaIterator) { | ||
return { | ||
name: iterator.meta.name | ||
}; | ||
} | ||
function runCancelledEffect(env, data, cb, _ref15) { | ||
var task = _ref15.task; | ||
cb(task.isCancelled()); | ||
} | ||
return getMetaInfo(fn); | ||
function runFlushEffect(env, channel$$1, cb) { | ||
channel$$1.flush(cb); | ||
} | ||
function runGetContextEffect(env, prop, cb, _ref16) { | ||
var task = _ref16.task; | ||
cb(task.context[prop]); | ||
} | ||
function runSetContextEffect(env, props, cb, _ref17) { | ||
var task = _ref17.task; | ||
__chunk_1.assignWithSymbols(task.context, props); | ||
cb(); | ||
} | ||
var effectRunnerMap = (_effectRunnerMap = {}, _effectRunnerMap[__chunk_1.TAKE] = runTakeEffect, _effectRunnerMap[__chunk_1.PUT] = runPutEffect, _effectRunnerMap[__chunk_1.ALL] = runAllEffect, _effectRunnerMap[__chunk_1.RACE] = runRaceEffect, _effectRunnerMap[__chunk_1.CALL] = runCallEffect, _effectRunnerMap[__chunk_1.CPS] = runCPSEffect, _effectRunnerMap[__chunk_1.FORK] = runForkEffect, _effectRunnerMap[__chunk_1.JOIN] = runJoinEffect, _effectRunnerMap[__chunk_1.CANCEL] = runCancelEffect, _effectRunnerMap[__chunk_1.SELECT] = runSelectEffect, _effectRunnerMap[__chunk_1.ACTION_CHANNEL] = runChannelEffect, _effectRunnerMap[__chunk_1.CANCELLED] = runCancelledEffect, _effectRunnerMap[__chunk_1.FLUSH] = runFlushEffect, _effectRunnerMap[__chunk_1.GET_CONTEXT] = runGetContextEffect, _effectRunnerMap[__chunk_1.SET_CONTEXT] = runSetContextEffect, _effectRunnerMap); | ||
/** | ||
Used to track a parent task and its forks | ||
In the new fork model, forked tasks are attached by default to their parent | ||
We model this using the concept of Parent task && main Task | ||
main task is the main flow of the current Generator, the parent tasks is the | ||
aggregation of the main tasks + all its forked tasks. | ||
Thus the whole model represents an execution tree with multiple branches (vs the | ||
linear execution tree in sequential (non parallel) programming) | ||
Used to track a parent task and its forks | ||
In the fork model, forked tasks are attached by default to their parent | ||
We model this using the concept of Parent task && main Task | ||
main task is the main flow of the current Generator, the parent tasks is the | ||
aggregation of the main tasks + all its forked tasks. | ||
Thus the whole model represents an execution tree with multiple branches (vs the | ||
linear execution tree in sequential (non parallel) programming) | ||
A parent tasks has the following semantics | ||
- It completes if all its forks either complete or all cancelled | ||
- If it's cancelled, all forks are cancelled as well | ||
- It aborts if any uncaught error bubbles up from forks | ||
- If it completes, the return value is the one returned by the main task | ||
**/ | ||
A parent tasks has the following semantics | ||
- It completes if all its forks either complete or all cancelled | ||
- If it's cancelled, all forks are cancelled as well | ||
- It aborts if any uncaught error bubbles up from forks | ||
- If it completes, the return value is the one returned by the main task | ||
**/ | ||
function forkQueue(mainTask, onAbort, cb) { | ||
var tasks = [], | ||
result, | ||
completed = false; | ||
function forkQueue(mainTask, onAbort, cont) { | ||
var tasks = []; | ||
var result; | ||
var completed = false; | ||
addTask(mainTask); | ||
@@ -461,12 +762,6 @@ | ||
var getTaskNames = function getTaskNames() { | ||
return tasks.map(function (t) { | ||
return t.meta.name; | ||
}); | ||
}; | ||
function abort(err) { | ||
onAbort(); | ||
cancelAll(); | ||
cb(err, true); | ||
cont(err, true); | ||
} | ||
@@ -494,7 +789,6 @@ | ||
completed = true; | ||
cb(result); | ||
cont(result); | ||
} | ||
} | ||
}; // task.cont.cancel = task.cancel | ||
}; | ||
} | ||
@@ -519,47 +813,196 @@ | ||
abort: abort, | ||
getTasks: getTasks, | ||
getTaskNames: getTaskNames | ||
getTasks: getTasks | ||
}; | ||
} | ||
function createTaskIterator(_ref) { | ||
var context = _ref.context, | ||
fn = _ref.fn, | ||
args = _ref.args; | ||
// there can be only a single saga error created at any given moment | ||
// catch synchronous failures; see #152 and #441 | ||
try { | ||
var result = fn.apply(context, args); // i.e. a generator function returns an iterator | ||
function formatLocation(fileName, lineNumber) { | ||
return fileName + "?" + lineNumber; | ||
} | ||
if (is.iterator(result)) { | ||
return result; | ||
function effectLocationAsString(effect) { | ||
var location = __chunk_1.getLocation(effect); | ||
if (location) { | ||
var code = location.code, | ||
fileName = location.fileName, | ||
lineNumber = location.lineNumber; | ||
var source = code + " " + formatLocation(fileName, lineNumber); | ||
return source; | ||
} | ||
return ''; | ||
} | ||
function sagaLocationAsString(sagaMeta) { | ||
var name = sagaMeta.name, | ||
location = sagaMeta.location; | ||
if (location) { | ||
return name + " " + formatLocation(location.fileName, location.lineNumber); | ||
} | ||
return name; | ||
} | ||
function cancelledTasksAsString(sagaStack) { | ||
var cancelledTasks = __chunk_1.flatMap(function (i) { | ||
return i.cancelledTasks; | ||
}, sagaStack); | ||
if (!cancelledTasks.length) { | ||
return ''; | ||
} | ||
return ['Tasks cancelled due to error:'].concat(cancelledTasks).join('\n'); | ||
} | ||
var crashedEffect = null; | ||
var sagaStack = []; | ||
var addSagaFrame = function addSagaFrame(frame) { | ||
frame.crashedEffect = crashedEffect; | ||
sagaStack.push(frame); | ||
}; | ||
var clear = function clear() { | ||
crashedEffect = null; | ||
sagaStack.length = 0; | ||
}; // this sets crashed effect for the soon-to-be-reported saga frame | ||
// this slightly streatches the singleton nature of this module into wrong direction | ||
// as it's even less obvious what's the data flow here, but it is what it is for now | ||
var setCrashedEffect = function setCrashedEffect(effect) { | ||
crashedEffect = effect; | ||
}; | ||
/** | ||
@returns {string} | ||
@example | ||
The above error occurred in task errorInPutSaga {pathToFile} | ||
when executing effect put({type: 'REDUCER_ACTION_ERROR_IN_PUT'}) {pathToFile} | ||
created by fetchSaga {pathToFile} | ||
created by rootSaga {pathToFile} | ||
*/ | ||
var toString = function toString() { | ||
var firstSaga = sagaStack[0], | ||
otherSagas = sagaStack.slice(1); | ||
var crashedEffectLocation = firstSaga.crashedEffect ? effectLocationAsString(firstSaga.crashedEffect) : null; | ||
var errorMessage = "The above error occurred in task " + sagaLocationAsString(firstSaga.meta) + (crashedEffectLocation ? " \n when executing effect " + crashedEffectLocation : ''); | ||
return [errorMessage].concat(otherSagas.map(function (s) { | ||
return " created by " + sagaLocationAsString(s.meta); | ||
}), [cancelledTasksAsString(sagaStack)]).join('\n'); | ||
}; | ||
function newTask(env, mainTask, parentContext, parentEffectId, meta, isRoot, cont) { | ||
var _task; | ||
var status = RUNNING; | ||
var taskResult; | ||
var taskError; | ||
var deferredEnd = null; | ||
var cancelledDueToErrorTasks = []; | ||
var context = Object.create(parentContext); | ||
var queue = forkQueue(mainTask, function onAbort() { | ||
cancelledDueToErrorTasks.push.apply(cancelledDueToErrorTasks, queue.getTasks().map(function (t) { | ||
return t.meta.name; | ||
})); | ||
}, end); | ||
/** | ||
This may be called by a parent generator to trigger/propagate cancellation | ||
cancel all pending tasks (including the main task), then end the current task. | ||
Cancellation propagates down to the whole execution tree held by this Parent task | ||
It's also propagated to all joiners of this task and their execution tree/joiners | ||
Cancellation is noop for terminated/Cancelled tasks tasks | ||
**/ | ||
function cancel() { | ||
if (status === RUNNING) { | ||
// Setting status to CANCELLED does not necessarily mean that the task/iterators are stopped | ||
// effects in the iterator's finally block will still be executed | ||
status = CANCELLED; | ||
queue.cancelAll(); // Ending with a TASK_CANCEL will propagate the Cancellation to all joiners | ||
end(symbols.TASK_CANCEL, false); | ||
} | ||
} | ||
var next = function next(value) { | ||
if (value === void 0) { | ||
value = result; | ||
function end(result, isErr) { | ||
if (!isErr) { | ||
// The status here may be RUNNING or CANCELLED | ||
// If the status is CANCELLED, then we do not need to change it here | ||
if (result === symbols.TASK_CANCEL) { | ||
status = CANCELLED; | ||
} else if (status !== CANCELLED) { | ||
status = DONE; | ||
} | ||
return { | ||
value: value, | ||
done: !is.promise(value) | ||
}; | ||
}; | ||
taskResult = result; | ||
deferredEnd && deferredEnd.resolve(result); | ||
} else { | ||
status = ABORTED; | ||
addSagaFrame({ | ||
meta: meta, | ||
cancelledTasks: cancelledDueToErrorTasks | ||
}); | ||
return __chunk_1.makeIterator(next); | ||
} catch (err) { | ||
// do not bubble up synchronous failures for detached forks | ||
// instead create a failed task. See #152 and #441 | ||
return __chunk_1.makeIterator(function () { | ||
throw err; | ||
if (task.isRoot) { | ||
var sagaStack = toString(); // we've dumped the saga stack to string and are passing it to user's code | ||
// we know that it won't be needed anymore and we need to clear it | ||
clear(); | ||
env.onError(result, { | ||
sagaStack: sagaStack | ||
}); | ||
} | ||
taskError = result; | ||
deferredEnd && deferredEnd.reject(result); | ||
} | ||
task.cont(result, isErr); | ||
task.joiners.forEach(function (joiner) { | ||
joiner.cb(result, isErr); | ||
}); | ||
task.joiners = null; | ||
} | ||
function setContext(props) { | ||
__chunk_1.assignWithSymbols(context, props); | ||
} | ||
function toPromise() { | ||
if (deferredEnd) { | ||
return deferredEnd.promise; | ||
} | ||
deferredEnd = deferred(); | ||
if (status === ABORTED) { | ||
deferredEnd.reject(taskError); | ||
} else if (status !== RUNNING) { | ||
deferredEnd.resolve(taskResult); | ||
} | ||
return deferredEnd.promise; | ||
} | ||
var task = (_task = {}, _task[symbols.TASK] = true, _task.id = parentEffectId, _task.meta = meta, _task.isRoot = isRoot, _task.context = context, _task.joiners = [], _task.queue = queue, _task.cancel = cancel, _task.cont = cont, _task.end = end, _task.setContext = setContext, _task.toPromise = toPromise, _task.isRunning = function isRunning() { | ||
return status === RUNNING; | ||
}, _task.isCancelled = function isCancelled() { | ||
return status === CANCELLED || status === RUNNING && mainTask.status === CANCELLED; | ||
}, _task.isAborted = function isAborted() { | ||
return status === ABORTED; | ||
}, _task.result = function result() { | ||
return taskResult; | ||
}, _task.error = function error() { | ||
return taskError; | ||
}, _task); | ||
return task; | ||
} | ||
function proc(env, iterator, parentContext, parentEffectId, meta, cont) { | ||
function proc(env, iterator, parentContext, parentEffectId, meta, isRoot, cont) { | ||
var taskContext = Object.create(parentContext); | ||
var finalRunEffect = env.finalizeRunEffect(runEffect); | ||
var crashedEffect = null; | ||
var cancelledDueToErrorTasks = []; | ||
/** | ||
@@ -572,24 +1015,27 @@ Tracks the current effect cancellation | ||
next.cancel = __chunk_1.noop; | ||
/** | ||
Creates a new task descriptor for this generator, We'll also create a main task | ||
to track the main flow (besides other forked tasks) | ||
**/ | ||
/** Creates a main task to track the main flow */ | ||
var task = newTask(parentEffectId, meta, cont); | ||
var mainTask = { | ||
meta: meta, | ||
cancel: cancelMain, | ||
_isRunning: true, | ||
_isCancelled: false | ||
status: RUNNING | ||
/** | ||
Creates a new task descriptor for this generator. | ||
A task is the aggregation of it's mainTask and all it's forked tasks. | ||
**/ | ||
}; | ||
var taskQueue = forkQueue(mainTask, function onAbort() { | ||
cancelledDueToErrorTasks.push.apply(cancelledDueToErrorTasks, taskQueue.getTaskNames()); | ||
}, end); | ||
/** | ||
cancellation of the main task. We'll simply resume the Generator with a Cancel | ||
**/ | ||
var task = newTask(env, mainTask, parentContext, parentEffectId, meta, isRoot, cont); | ||
var executingContext = { | ||
task: task, | ||
digestEffect: digestEffect | ||
/** | ||
cancellation of the main task. We'll simply resume the Generator with a TASK_CANCEL | ||
**/ | ||
}; | ||
function cancelMain() { | ||
if (mainTask._isRunning && !mainTask._isCancelled) { | ||
mainTask._isCancelled = true; | ||
if (mainTask.status === RUNNING) { | ||
mainTask.status = CANCELLED; | ||
next(symbols.TASK_CANCEL); | ||
@@ -599,26 +1045,2 @@ } | ||
/** | ||
This may be called by a parent generator to trigger/propagate cancellation | ||
cancel all pending tasks (including the main task), then end the current task. | ||
Cancellation propagates down to the whole execution tree holded by this Parent task | ||
It's also propagated to all joiners of this task and their execution tree/joiners | ||
Cancellation is noop for terminated/Cancelled tasks tasks | ||
**/ | ||
function cancel() { | ||
/** | ||
We need to check both Running and Cancelled status | ||
Tasks can be Cancelled but still Running | ||
**/ | ||
if (task._isRunning && !task._isCancelled) { | ||
task._isCancelled = true; | ||
taskQueue.cancelAll(); | ||
/** | ||
Ending with a Never result will propagate the Cancellation to all joiners | ||
**/ | ||
end(symbols.TASK_CANCEL); | ||
} | ||
} | ||
/** | ||
attaches cancellation logic to this task's continuation | ||
@@ -629,3 +1051,3 @@ this will permit cancellation to propagate down the call chain | ||
cont && (cont.cancel = cancel); // kicks up the generator | ||
cont.cancel = task.cancel; // kicks up the generator | ||
@@ -636,13 +1058,12 @@ next(); // then return the task descriptor to the caller | ||
/** | ||
This is the generator driver | ||
It's a recursive async/continuation function which calls itself | ||
until the generator terminates or throws | ||
**/ | ||
* This is the generator driver | ||
* It's a recursive async/continuation function which calls itself | ||
* until the generator terminates or throws | ||
* @param {internal commands(TASK_CANCEL | TERMINATE) | any} arg - value, generator will be resumed with. | ||
* @param {boolean} isErr - the flag shows if effect finished with an error | ||
* | ||
* receives either (command | effect result, false) or (any thrown thing, true) | ||
*/ | ||
function next(arg, isErr) { | ||
// Preventive measure. If we end up here, then there is really something wrong | ||
if (!mainTask._isRunning) { | ||
throw new Error('Trying to resume an already finished generator'); | ||
} | ||
try { | ||
@@ -652,3 +1073,5 @@ var result; | ||
if (isErr) { | ||
result = iterator.throw(arg); | ||
result = iterator.throw(arg); // user handled the error, we can clear bookkept values | ||
clear(); | ||
} else if (__chunk_1.shouldCancel(arg)) { | ||
@@ -661,3 +1084,3 @@ /** | ||
**/ | ||
mainTask._isCancelled = true; | ||
mainTask.status = CANCELLED; | ||
/** | ||
@@ -687,3 +1110,3 @@ Cancels the current effect; this will propagate the cancellation down to any called tasks | ||
if (!result.done) { | ||
digestEffect(result.value, parentEffectId, '', next); | ||
digestEffect(result.value, parentEffectId, next); | ||
} else { | ||
@@ -693,11 +1116,14 @@ /** | ||
**/ | ||
mainTask._isRunning = false; | ||
if (mainTask.status !== CANCELLED) { | ||
mainTask.status = DONE; | ||
} | ||
mainTask.cont(result.value); | ||
} | ||
} catch (error) { | ||
if (mainTask._isCancelled) { | ||
env.logError(error); | ||
if (mainTask.status === CANCELLED) { | ||
throw error; | ||
} | ||
mainTask._isRunning = false; | ||
mainTask.status = ABORTED; | ||
mainTask.cont(error, true); | ||
@@ -707,40 +1133,2 @@ } | ||
function end(result, isErr) { | ||
task._isRunning = false; | ||
if (!isErr) { | ||
task._result = result; | ||
task._deferredEnd && task._deferredEnd.resolve(result); | ||
} else { | ||
addSagaStack(result, { | ||
meta: meta, | ||
effect: crashedEffect, | ||
cancelledTasks: cancelledDueToErrorTasks | ||
}); | ||
if (!task.cont) { | ||
if (result && result.sagaStack) { | ||
result.sagaStack = sagaStackToString(result.sagaStack); | ||
} | ||
if (env.onError) { | ||
env.onError(result); | ||
} else { | ||
// TODO: could we skip this when _deferredEnd is attached? | ||
env.logError(result); | ||
} | ||
} | ||
task._error = result; | ||
task._isAborted = true; | ||
task._deferredEnd && task._deferredEnd.reject(result); | ||
} | ||
task.cont && task.cont(result, isErr); | ||
task.joiners.forEach(function (j) { | ||
return j.cb(result, isErr); | ||
}); | ||
task.joiners = null; | ||
} | ||
function runEffect(effect, effectId, currCb) { | ||
@@ -762,7 +1150,9 @@ /** | ||
} else if (is.iterator(effect)) { | ||
resolveIterator(effect, effectId, meta, currCb); | ||
// resolve iterator | ||
proc(env, effect, task.context, effectId, meta, | ||
/* isRoot */ | ||
false, currCb); | ||
} else if (effect && effect[symbols.IO]) { | ||
var type = effect.type, | ||
payload = effect.payload; | ||
if (type === __chunk_2.TAKE) runTakeEffect(payload, currCb);else if (type === __chunk_2.PUT) runPutEffect(payload, currCb);else if (type === __chunk_2.ALL) runAllEffect(payload, effectId, currCb);else if (type === __chunk_2.RACE) runRaceEffect(payload, effectId, currCb);else if (type === __chunk_2.CALL) runCallEffect(payload, effectId, currCb);else if (type === __chunk_2.CPS) runCPSEffect(payload, currCb);else if (type === __chunk_2.FORK) runForkEffect(payload, effectId, currCb);else if (type === __chunk_2.JOIN) runJoinEffect(payload, currCb);else if (type === __chunk_2.CANCEL) runCancelEffect(payload, currCb);else if (type === __chunk_2.SELECT) runSelectEffect(payload, currCb);else if (type === __chunk_2.ACTION_CHANNEL) runChannelEffect(payload, currCb);else if (type === __chunk_2.FLUSH) runFlushEffect(payload, currCb);else if (type === __chunk_2.CANCELLED) runCancelledEffect(payload, currCb);else if (type === __chunk_2.GET_CONTEXT) runGetContextEffect(payload, currCb);else if (type === __chunk_2.SET_CONTEXT) runSetContextEffect(payload, currCb);else currCb(effect); | ||
var effectRunner = effectRunnerMap[effect.type]; | ||
effectRunner(env, effect.payload, currCb, executingContext); | ||
} else { | ||
@@ -774,3 +1164,3 @@ // anything else returned as is | ||
function digestEffect(effect, parentEffectId, label, cb) { | ||
function digestEffect(effect, parentEffectId, cb, label) { | ||
if (label === void 0) { | ||
@@ -780,3 +1170,3 @@ label = ''; | ||
var effectId = __chunk_1.uid(); | ||
var effectId = nextEffectId(); | ||
env.sagaMonitor && env.sagaMonitor.effectTriggered({ | ||
@@ -813,3 +1203,3 @@ effectId: effectId, | ||
if (isErr) { | ||
crashedEffect = effect; | ||
setCrashedEffect(effect); | ||
} | ||
@@ -830,14 +1220,4 @@ | ||
effectSettled = true; | ||
/** | ||
propagates cancel downward | ||
catch uncaught cancellations errors; since we can no longer call the completion | ||
callback, log errors raised during cancellations into the console | ||
**/ | ||
currCb.cancel(); // propagates cancel downward | ||
try { | ||
currCb.cancel(); | ||
} catch (err) { | ||
env.logError(err); | ||
} | ||
currCb.cancel = __chunk_1.noop; // defensive measure | ||
@@ -850,378 +1230,16 @@ | ||
} | ||
} | ||
function resolvePromise(promise, cb) { | ||
var cancelPromise = promise[symbols.CANCEL]; | ||
function runSaga(_ref, saga) { | ||
var _ref$channel = _ref.channel, | ||
channel$$1 = _ref$channel === void 0 ? stdChannel() : _ref$channel, | ||
dispatch = _ref.dispatch, | ||
getState = _ref.getState, | ||
_ref$context = _ref.context, | ||
context = _ref$context === void 0 ? {} : _ref$context, | ||
sagaMonitor = _ref.sagaMonitor, | ||
effectMiddlewares = _ref.effectMiddlewares, | ||
_ref$onError = _ref.onError, | ||
onError = _ref$onError === void 0 ? __chunk_1.logError : _ref$onError; | ||
if (is.func(cancelPromise)) { | ||
cb.cancel = cancelPromise; | ||
} else if (is.func(promise.abort)) { | ||
cb.cancel = function () { | ||
return promise.abort(); | ||
}; | ||
} | ||
promise.then(cb, function (error) { | ||
return cb(error, true); | ||
}); | ||
} | ||
function resolveIterator(iterator, effectId, meta, cb) { | ||
proc(env, iterator, taskContext, effectId, meta, cb); | ||
} | ||
function runTakeEffect(_ref2, cb) { | ||
var _ref2$channel = _ref2.channel, | ||
channel$$1 = _ref2$channel === void 0 ? env.stdChannel : _ref2$channel, | ||
pattern = _ref2.pattern, | ||
maybe = _ref2.maybe; | ||
var takeCb = function takeCb(input) { | ||
if (input instanceof Error) { | ||
cb(input, true); | ||
return; | ||
} | ||
if (isEnd(input) && !maybe) { | ||
cb(symbols.TERMINATE); | ||
return; | ||
} | ||
cb(input); | ||
}; | ||
try { | ||
channel$$1.take(takeCb, is.notUndef(pattern) ? matcher(pattern) : null); | ||
} catch (err) { | ||
cb(err, true); | ||
return; | ||
} | ||
cb.cancel = takeCb.cancel; | ||
} | ||
function runPutEffect(_ref3, cb) { | ||
var channel$$1 = _ref3.channel, | ||
action = _ref3.action, | ||
resolve = _ref3.resolve; | ||
/** | ||
Schedule the put in case another saga is holding a lock. | ||
The put will be executed atomically. ie nested puts will execute after | ||
this put has terminated. | ||
**/ | ||
asap(function () { | ||
var result; | ||
try { | ||
result = (channel$$1 ? channel$$1.put : env.dispatch)(action); | ||
} catch (error) { | ||
cb(error, true); | ||
return; | ||
} | ||
if (resolve && is.promise(result)) { | ||
resolvePromise(result, cb); | ||
} else { | ||
cb(result); | ||
} | ||
}); // Put effects are non cancellables | ||
} | ||
function runCallEffect(_ref4, effectId, cb) { | ||
var context = _ref4.context, | ||
fn = _ref4.fn, | ||
args = _ref4.args; | ||
// catch synchronous failures; see #152 | ||
try { | ||
var result = fn.apply(context, args); | ||
if (is.promise(result)) { | ||
resolvePromise(result, cb); | ||
return; | ||
} | ||
if (is.iterator(result)) { | ||
resolveIterator(result, effectId, getMetaInfo(fn), cb); | ||
return; | ||
} | ||
cb(result); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runCPSEffect(_ref5, cb) { | ||
var context = _ref5.context, | ||
fn = _ref5.fn, | ||
args = _ref5.args; | ||
// CPS (ie node style functions) can define their own cancellation logic | ||
// by setting cancel field on the cb | ||
// catch synchronous failures; see #152 | ||
try { | ||
var cpsCb = function cpsCb(err, res) { | ||
return is.undef(err) ? cb(res) : cb(err, true); | ||
}; | ||
fn.apply(context, args.concat(cpsCb)); | ||
if (cpsCb.cancel) { | ||
cb.cancel = function () { | ||
return cpsCb.cancel(); | ||
}; | ||
} | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runForkEffect(_ref6, effectId, cb) { | ||
var context = _ref6.context, | ||
fn = _ref6.fn, | ||
args = _ref6.args, | ||
detached = _ref6.detached; | ||
var taskIterator = createTaskIterator({ | ||
context: context, | ||
fn: fn, | ||
args: args | ||
}); | ||
var meta = getIteratorMetaInfo(taskIterator, fn); | ||
try { | ||
suspend(); | ||
var _task = proc(env, taskIterator, taskContext, effectId, meta, detached ? null : __chunk_1.noop); | ||
if (detached) { | ||
cb(_task); | ||
} else { | ||
if (_task._isRunning) { | ||
taskQueue.addTask(_task); | ||
cb(_task); | ||
} else if (_task._error) { | ||
taskQueue.abort(_task._error); | ||
} else { | ||
cb(_task); | ||
} | ||
} | ||
} finally { | ||
flush(); | ||
} // Fork effects are non cancellables | ||
} | ||
function runJoinEffect(taskOrTasks, cb) { | ||
if (is.array(taskOrTasks)) { | ||
if (taskOrTasks.length === 0) { | ||
cb([]); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(taskOrTasks, cb); | ||
taskOrTasks.forEach(function (t, i) { | ||
joinSingleTask(t, childCallbacks[i]); | ||
}); | ||
} else { | ||
joinSingleTask(taskOrTasks, cb); | ||
} | ||
} | ||
function joinSingleTask(taskToJoin, cb) { | ||
if (taskToJoin.isRunning()) { | ||
var joiner = { | ||
task: task, | ||
cb: cb | ||
}; | ||
cb.cancel = function () { | ||
return __chunk_1.remove(taskToJoin.joiners, joiner); | ||
}; | ||
taskToJoin.joiners.push(joiner); | ||
} else { | ||
if (taskToJoin.isAborted()) { | ||
cb(taskToJoin.error(), true); | ||
} else { | ||
cb(taskToJoin.result()); | ||
} | ||
} | ||
} | ||
function runCancelEffect(taskOrTasks, cb) { | ||
if (taskOrTasks === symbols.SELF_CANCELLATION) { | ||
cancelSingleTask(task); | ||
} else if (is.array(taskOrTasks)) { | ||
taskOrTasks.forEach(cancelSingleTask); | ||
} else { | ||
cancelSingleTask(taskOrTasks); | ||
} | ||
cb(); // cancel effects are non cancellables | ||
} | ||
function cancelSingleTask(taskToCancel) { | ||
if (taskToCancel.isRunning()) { | ||
taskToCancel.cancel(); | ||
} | ||
} | ||
function runAllEffect(effects, effectId, cb) { | ||
var keys = Object.keys(effects); | ||
if (keys.length === 0) { | ||
cb(is.array(effects) ? [] : {}); | ||
return; | ||
} | ||
var childCallbacks = __chunk_1.createAllStyleChildCallbacks(effects, cb); | ||
keys.forEach(function (key) { | ||
return digestEffect(effects[key], effectId, key, childCallbacks[key]); | ||
}); | ||
} | ||
function runRaceEffect(effects, effectId, cb) { | ||
var completed; | ||
var keys = Object.keys(effects); | ||
var childCbs = {}; | ||
keys.forEach(function (key) { | ||
var chCbAtKey = function chCbAtKey(res, isErr) { | ||
if (completed) { | ||
return; | ||
} | ||
if (isErr || __chunk_1.shouldComplete(res)) { | ||
// Race Auto cancellation | ||
cb.cancel(); | ||
cb(res, isErr); | ||
} else { | ||
var _response; | ||
cb.cancel(); | ||
completed = true; | ||
var response = (_response = {}, _response[key] = res, _response); | ||
cb(is.array(effects) ? __chunk_1.array.from(_extends({}, response, { | ||
length: keys.length | ||
})) : response); | ||
} | ||
}; | ||
chCbAtKey.cancel = __chunk_1.noop; | ||
childCbs[key] = chCbAtKey; | ||
}); | ||
cb.cancel = function () { | ||
// prevents unnecessary cancellation | ||
if (!completed) { | ||
completed = true; | ||
keys.forEach(function (key) { | ||
return childCbs[key].cancel(); | ||
}); | ||
} | ||
}; | ||
keys.forEach(function (key) { | ||
if (completed) { | ||
return; | ||
} | ||
digestEffect(effects[key], effectId, key, childCbs[key]); | ||
}); | ||
} | ||
function runSelectEffect(_ref7, cb) { | ||
var selector = _ref7.selector, | ||
args = _ref7.args; | ||
try { | ||
var state = selector.apply(void 0, [env.getState()].concat(args)); | ||
cb(state); | ||
} catch (error) { | ||
cb(error, true); | ||
} | ||
} | ||
function runChannelEffect(_ref8, cb) { | ||
var pattern = _ref8.pattern, | ||
buffer = _ref8.buffer; | ||
// TODO: rethink how END is handled | ||
var chan = channel(buffer); | ||
var match = matcher(pattern); | ||
var taker = function taker(action) { | ||
if (!isEnd(action)) { | ||
env.stdChannel.take(taker, match); | ||
} | ||
chan.put(action); | ||
}; | ||
var close = chan.close; | ||
chan.close = function () { | ||
taker.cancel(); | ||
close(); | ||
}; | ||
env.stdChannel.take(taker, match); | ||
cb(chan); | ||
} | ||
function runCancelledEffect(data, cb) { | ||
cb(Boolean(mainTask._isCancelled)); | ||
} | ||
function runFlushEffect(channel$$1, cb) { | ||
channel$$1.flush(cb); | ||
} | ||
function runGetContextEffect(prop, cb) { | ||
cb(taskContext[prop]); | ||
} | ||
function runSetContextEffect(props, cb) { | ||
__chunk_1.assignWithSymbols(taskContext, props); | ||
cb(); | ||
} | ||
function newTask(id, meta, cont) { | ||
var _task2; | ||
var task = (_task2 = {}, _task2[symbols.TASK] = true, _task2.id = id, _task2.meta = meta, _task2._deferredEnd = null, _task2.toPromise = function toPromise() { | ||
if (task._deferredEnd) { | ||
return task._deferredEnd.promise; | ||
} | ||
var def = deferred(); | ||
task._deferredEnd = def; | ||
if (!task._isRunning) { | ||
if (task._isAborted) { | ||
def.reject(task._error); | ||
} else { | ||
def.resolve(task._result); | ||
} | ||
} | ||
return def.promise; | ||
}, _task2.cont = cont, _task2.joiners = [], _task2.cancel = cancel, _task2._isRunning = true, _task2._isCancelled = false, _task2._isAborted = false, _task2._result = undefined, _task2._error = undefined, _task2.isRunning = function isRunning() { | ||
return task._isRunning; | ||
}, _task2.isCancelled = function isCancelled() { | ||
return task._isCancelled; | ||
}, _task2.isAborted = function isAborted() { | ||
return task._isAborted; | ||
}, _task2.result = function result() { | ||
return task._result; | ||
}, _task2.error = function error() { | ||
return task._error; | ||
}, _task2.setContext = function setContext(props) { | ||
__chunk_1.assignWithSymbols(taskContext, props); | ||
}, _task2); | ||
return task; | ||
} | ||
} | ||
function runSaga(options, saga) { | ||
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { | ||
@@ -1233,13 +1251,3 @@ args[_key - 2] = arguments[_key]; | ||
var _options$channel = options.channel, | ||
channel$$1 = _options$channel === void 0 ? stdChannel() : _options$channel, | ||
dispatch = options.dispatch, | ||
getState = options.getState, | ||
_options$context = options.context, | ||
context = _options$context === void 0 ? {} : _options$context, | ||
sagaMonitor = options.sagaMonitor, | ||
logger = options.logger, | ||
effectMiddlewares = options.effectMiddlewares, | ||
onError = options.onError; | ||
var effectId = __chunk_1.uid(); | ||
var effectId = nextEffectId(); | ||
@@ -1261,17 +1269,9 @@ if (sagaMonitor) { | ||
var log = logger || __chunk_1.log; | ||
var finalizeRunEffect; | ||
var logError = function logError(err) { | ||
log('error', err); | ||
if (effectMiddlewares) { | ||
var middleware = redux.compose.apply(void 0, effectMiddlewares); | ||
if (err && err.sagaStack) { | ||
log('error', err.sagaStack); | ||
} | ||
}; | ||
var middleware = effectMiddlewares && redux.compose.apply(void 0, effectMiddlewares); | ||
var finalizeRunEffect = function finalizeRunEffect(runEffect) { | ||
if (is.func(middleware)) { | ||
return function finalRunEffect(effect, effectId, currCb) { | ||
finalizeRunEffect = function finalizeRunEffect(runEffect) { | ||
return function (effect, effectId, currCb) { | ||
var plainRunEffect = function plainRunEffect(eff) { | ||
@@ -1283,21 +1283,20 @@ return runEffect(eff, effectId, currCb); | ||
}; | ||
} else { | ||
return runEffect; | ||
} | ||
}; | ||
}; | ||
} else { | ||
finalizeRunEffect = __chunk_1.identity; | ||
} | ||
var env = { | ||
stdChannel: channel$$1, | ||
channel: channel$$1, | ||
dispatch: __chunk_1.wrapSagaDispatch(dispatch), | ||
getState: getState, | ||
sagaMonitor: sagaMonitor, | ||
logError: logError, | ||
onError: onError, | ||
finalizeRunEffect: finalizeRunEffect | ||
}; | ||
return immediately(function () { | ||
var task = proc(env, iterator, context, effectId, __chunk_1.getMetaInfo(saga), | ||
/* isRoot */ | ||
true, __chunk_1.noop); | ||
try { | ||
suspend(); | ||
var task = proc(env, iterator, context, effectId, getMetaInfo(saga), null); | ||
if (sagaMonitor) { | ||
@@ -1308,5 +1307,3 @@ sagaMonitor.effectResolved(effectId, task); | ||
return task; | ||
} finally { | ||
flush(); | ||
} | ||
}); | ||
} | ||
@@ -1322,8 +1319,7 @@ | ||
context = _ref2$context === void 0 ? {} : _ref2$context, | ||
options = _objectWithoutPropertiesLoose(_ref2, ["context"]); | ||
_ref2$channel = _ref2.channel, | ||
channel$$1 = _ref2$channel === void 0 ? stdChannel() : _ref2$channel, | ||
sagaMonitor = _ref2.sagaMonitor, | ||
options = _objectWithoutPropertiesLoose(_ref2, ["context", "channel", "sagaMonitor"]); | ||
var sagaMonitor = options.sagaMonitor, | ||
logger = options.logger, | ||
onError = options.onError, | ||
effectMiddlewares = options.effectMiddlewares; | ||
var boundRunSaga; | ||
@@ -1334,5 +1330,3 @@ | ||
dispatch = _ref3.dispatch; | ||
var channel$$1 = stdChannel(); | ||
channel$$1.put = (options.emitter || __chunk_1.identity)(channel$$1.put); | ||
boundRunSaga = runSaga.bind(null, { | ||
boundRunSaga = runSaga.bind(null, _extends({}, options, { | ||
context: context, | ||
@@ -1342,7 +1336,4 @@ channel: channel$$1, | ||
getState: getState, | ||
sagaMonitor: sagaMonitor, | ||
logger: logger, | ||
onError: onError, | ||
effectMiddlewares: effectMiddlewares | ||
}); | ||
sagaMonitor: sagaMonitor | ||
})); | ||
return function (next) { | ||
@@ -1375,6 +1366,6 @@ return function (action) { | ||
exports.buffers = __chunk_1.buffers; | ||
exports.detach = __chunk_1.detach; | ||
exports.CANCEL = symbols.CANCEL; | ||
exports.SAGA_LOCATION = symbols.SAGA_LOCATION; | ||
exports.buffers = __chunk_2.buffers; | ||
exports.detach = __chunk_2.detach; | ||
exports.default = sagaMiddlewareFactory; | ||
@@ -1381,0 +1372,0 @@ exports.runSaga = runSaga; |
@@ -6,4 +6,3 @@ 'use strict'; | ||
var is = require('@redux-saga/is'); | ||
var __chunk_1 = require('./chunk-5caa0f1a.js'); | ||
var __chunk_2 = require('./chunk-062c0282.js'); | ||
var __chunk_1 = require('./chunk-0e1a6d35.js'); | ||
require('@babel/runtime/helpers/extends'); | ||
@@ -73,3 +72,3 @@ require('@redux-saga/symbols'); | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
@@ -80,3 +79,3 @@ | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -114,3 +113,3 @@ }; | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
@@ -121,3 +120,3 @@ | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -129,3 +128,3 @@ }; | ||
done: false, | ||
value: __chunk_2.cancel(task) | ||
value: __chunk_1.cancel(task) | ||
}; | ||
@@ -179,3 +178,3 @@ }; | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
@@ -186,3 +185,3 @@ | ||
done: false, | ||
value: __chunk_2.call.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.call.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -222,3 +221,3 @@ }; | ||
done: false, | ||
value: __chunk_2.actionChannel(pattern, __chunk_2.sliding(1)) | ||
value: __chunk_1.actionChannel(pattern, __chunk_1.sliding(1)) | ||
}; | ||
@@ -229,3 +228,3 @@ | ||
done: false, | ||
value: __chunk_2.take(channel) | ||
value: __chunk_1.take(channel) | ||
}; | ||
@@ -237,3 +236,3 @@ }; | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -244,3 +243,3 @@ }; | ||
done: false, | ||
value: __chunk_2.delay(delayLength) | ||
value: __chunk_1.delay(delayLength) | ||
}; | ||
@@ -295,7 +294,7 @@ | ||
done: false, | ||
value: __chunk_2.call.apply(void 0, [fn].concat(args)) | ||
value: __chunk_1.call.apply(void 0, [fn].concat(args)) | ||
}; | ||
var yDelay = { | ||
done: false, | ||
value: __chunk_2.delay(delayLength) | ||
value: __chunk_1.delay(delayLength) | ||
}; | ||
@@ -338,9 +337,9 @@ return fsmIterator({ | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
var yRace = { | ||
done: false, | ||
value: __chunk_2.race({ | ||
action: __chunk_2.take(patternOrChannel), | ||
debounce: __chunk_2.delay(delayLength) | ||
value: __chunk_1.race({ | ||
action: __chunk_1.take(patternOrChannel), | ||
debounce: __chunk_1.delay(delayLength) | ||
}) | ||
@@ -352,3 +351,3 @@ }; | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -414,3 +413,3 @@ }; | ||
return __chunk_2.fork.apply(void 0, [takeEvery, patternOrChannel, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [takeEvery, patternOrChannel, worker].concat(args)); | ||
} | ||
@@ -426,3 +425,3 @@ function takeLatest$1(patternOrChannel, worker) { | ||
return __chunk_2.fork.apply(void 0, [takeLatest, patternOrChannel, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [takeLatest, patternOrChannel, worker].concat(args)); | ||
} | ||
@@ -438,3 +437,3 @@ function takeLeading$1(patternOrChannel, worker) { | ||
return __chunk_2.fork.apply(void 0, [takeLeading, patternOrChannel, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [takeLeading, patternOrChannel, worker].concat(args)); | ||
} | ||
@@ -451,3 +450,3 @@ function throttle$1(ms, pattern, worker) { | ||
return __chunk_2.fork.apply(void 0, [throttle, ms, pattern, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [throttle, ms, pattern, worker].concat(args)); | ||
} | ||
@@ -459,3 +458,3 @@ function retry$1(maxTries, delayLength, worker) { | ||
return __chunk_2.call.apply(void 0, [retry, maxTries, delayLength, worker].concat(args)); | ||
return __chunk_1.call.apply(void 0, [retry, maxTries, delayLength, worker].concat(args)); | ||
} | ||
@@ -467,26 +466,26 @@ function debounce(delayLength, pattern, worker) { | ||
return __chunk_2.fork.apply(void 0, [debounceHelper, delayLength, pattern, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [debounceHelper, delayLength, pattern, worker].concat(args)); | ||
} | ||
exports.effectTypes = __chunk_2.effectTypes; | ||
exports.take = __chunk_2.take; | ||
exports.takeMaybe = __chunk_2.takeMaybe; | ||
exports.put = __chunk_2.put; | ||
exports.putResolve = __chunk_2.putResolve; | ||
exports.all = __chunk_2.all; | ||
exports.race = __chunk_2.race; | ||
exports.call = __chunk_2.call; | ||
exports.apply = __chunk_2.apply; | ||
exports.cps = __chunk_2.cps; | ||
exports.fork = __chunk_2.fork; | ||
exports.spawn = __chunk_2.spawn; | ||
exports.join = __chunk_2.join; | ||
exports.cancel = __chunk_2.cancel; | ||
exports.select = __chunk_2.select; | ||
exports.actionChannel = __chunk_2.actionChannel; | ||
exports.cancelled = __chunk_2.cancelled; | ||
exports.flush = __chunk_2.flush; | ||
exports.getContext = __chunk_2.getContext; | ||
exports.setContext = __chunk_2.setContext; | ||
exports.delay = __chunk_2.delay; | ||
exports.effectTypes = __chunk_1.effectTypes; | ||
exports.take = __chunk_1.take; | ||
exports.takeMaybe = __chunk_1.takeMaybe; | ||
exports.put = __chunk_1.put; | ||
exports.putResolve = __chunk_1.putResolve; | ||
exports.all = __chunk_1.all; | ||
exports.race = __chunk_1.race; | ||
exports.call = __chunk_1.call; | ||
exports.apply = __chunk_1.apply; | ||
exports.cps = __chunk_1.cps; | ||
exports.fork = __chunk_1.fork; | ||
exports.spawn = __chunk_1.spawn; | ||
exports.join = __chunk_1.join; | ||
exports.cancel = __chunk_1.cancel; | ||
exports.select = __chunk_1.select; | ||
exports.actionChannel = __chunk_1.actionChannel; | ||
exports.cancelled = __chunk_1.cancelled; | ||
exports.flush = __chunk_1.flush; | ||
exports.getContext = __chunk_1.getContext; | ||
exports.setContext = __chunk_1.setContext; | ||
exports.delay = __chunk_1.delay; | ||
exports.debounce = debounce; | ||
@@ -493,0 +492,0 @@ exports.retry = retry$1; |
@@ -1,5 +0,4 @@ | ||
import { notUndef, func, object, iterator, array, buffer, pattern, multicast, channel, undef, string, task, stringableFunc, symbol, promise } from '@redux-saga/is'; | ||
import { l as makeIterator, c as check } from './chunk-e16e13ae.js'; | ||
import { w as take, x as fork, y as cancel, z as call, A as actionChannel, B as delay, a as none, b as fixed, c as dropping, d as sliding, e as expanding, f as buffers, C as race, g as TAKE, h as PUT, i as ALL, j as RACE, k as CALL, l as CPS, m as FORK, n as JOIN, o as CANCEL, p as SELECT, q as ACTION_CHANNEL, r as CANCELLED, s as FLUSH, t as GET_CONTEXT, u as SET_CONTEXT, v as effectTypes } from './chunk-7bc4cf1d.js'; | ||
export { v as effectTypes, w as take, E as takeMaybe, F as put, G as putResolve, H as all, C as race, z as call, I as apply, J as cps, x as fork, K as spawn, L as join, y as cancel, M as select, A as actionChannel, N as cancelled, O as flush, P as getContext, Q as setContext, B as delay } from './chunk-7bc4cf1d.js'; | ||
import { channel, object, func, iterator, notUndef, array, buffer, pattern, multicast, undef, string, task, promise, stringableFunc, symbol } from '@redux-saga/is'; | ||
import { E as makeIterator, R as take, S as fork, T as cancel, U as call, V as actionChannel, W as delay, f as none, g as fixed, h as dropping, i as sliding, j as expanding, k as buffers, X as race, b as check, l as TAKE, m as PUT, n as ALL, o as RACE, p as CALL, q as CPS, r as FORK, s as JOIN, t as CANCEL, u as SELECT, v as ACTION_CHANNEL, w as CANCELLED, x as FLUSH, y as GET_CONTEXT, z as SET_CONTEXT, A as effectTypes } from './chunk-b503a2ff.js'; | ||
export { A as effectTypes, R as take, Z as takeMaybe, _ as put, $ as putResolve, a0 as all, X as race, U as call, a1 as apply, a2 as cps, S as fork, a3 as spawn, a4 as join, T as cancel, a5 as select, V as actionChannel, a6 as cancelled, a7 as flush, a8 as getContext, a9 as setContext, W as delay } from './chunk-b503a2ff.js'; | ||
import '@babel/runtime/helpers/esm/extends'; | ||
@@ -6,0 +5,0 @@ import '@redux-saga/symbols'; |
@@ -6,4 +6,3 @@ 'use strict'; | ||
var is = require('@redux-saga/is'); | ||
var __chunk_1 = require('./chunk-795916d1.js'); | ||
var __chunk_2 = require('./chunk-51a22d4b.js'); | ||
var __chunk_1 = require('./chunk-0077808e.js'); | ||
require('@babel/runtime/helpers/extends'); | ||
@@ -73,3 +72,3 @@ require('@redux-saga/symbols'); | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
@@ -80,3 +79,3 @@ | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -114,3 +113,3 @@ }; | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
@@ -121,3 +120,3 @@ | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -129,3 +128,3 @@ }; | ||
done: false, | ||
value: __chunk_2.cancel(task) | ||
value: __chunk_1.cancel(task) | ||
}; | ||
@@ -179,3 +178,3 @@ }; | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
@@ -186,3 +185,3 @@ | ||
done: false, | ||
value: __chunk_2.call.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.call.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -222,3 +221,3 @@ }; | ||
done: false, | ||
value: __chunk_2.actionChannel(pattern, __chunk_2.sliding(1)) | ||
value: __chunk_1.actionChannel(pattern, __chunk_1.sliding(1)) | ||
}; | ||
@@ -229,3 +228,3 @@ | ||
done: false, | ||
value: __chunk_2.take(channel) | ||
value: __chunk_1.take(channel) | ||
}; | ||
@@ -237,3 +236,3 @@ }; | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -244,3 +243,3 @@ }; | ||
done: false, | ||
value: __chunk_2.delay(delayLength) | ||
value: __chunk_1.delay(delayLength) | ||
}; | ||
@@ -295,7 +294,7 @@ | ||
done: false, | ||
value: __chunk_2.call.apply(void 0, [fn].concat(args)) | ||
value: __chunk_1.call.apply(void 0, [fn].concat(args)) | ||
}; | ||
var yDelay = { | ||
done: false, | ||
value: __chunk_2.delay(delayLength) | ||
value: __chunk_1.delay(delayLength) | ||
}; | ||
@@ -338,9 +337,9 @@ return fsmIterator({ | ||
done: false, | ||
value: __chunk_2.take(patternOrChannel) | ||
value: __chunk_1.take(patternOrChannel) | ||
}; | ||
var yRace = { | ||
done: false, | ||
value: __chunk_2.race({ | ||
action: __chunk_2.take(patternOrChannel), | ||
debounce: __chunk_2.delay(delayLength) | ||
value: __chunk_1.race({ | ||
action: __chunk_1.take(patternOrChannel), | ||
debounce: __chunk_1.delay(delayLength) | ||
}) | ||
@@ -352,3 +351,3 @@ }; | ||
done: false, | ||
value: __chunk_2.fork.apply(void 0, [worker].concat(args, [ac])) | ||
value: __chunk_1.fork.apply(void 0, [worker].concat(args, [ac])) | ||
}; | ||
@@ -406,3 +405,3 @@ }; | ||
return __chunk_2.fork.apply(void 0, [takeEvery, patternOrChannel, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [takeEvery, patternOrChannel, worker].concat(args)); | ||
} | ||
@@ -415,3 +414,3 @@ function takeLatest$1(patternOrChannel, worker) { | ||
return __chunk_2.fork.apply(void 0, [takeLatest, patternOrChannel, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [takeLatest, patternOrChannel, worker].concat(args)); | ||
} | ||
@@ -424,3 +423,3 @@ function takeLeading$1(patternOrChannel, worker) { | ||
return __chunk_2.fork.apply(void 0, [takeLeading, patternOrChannel, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [takeLeading, patternOrChannel, worker].concat(args)); | ||
} | ||
@@ -433,3 +432,3 @@ function throttle$1(ms, pattern, worker) { | ||
return __chunk_2.fork.apply(void 0, [throttle, ms, pattern, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [throttle, ms, pattern, worker].concat(args)); | ||
} | ||
@@ -441,3 +440,3 @@ function retry$1(maxTries, delayLength, worker) { | ||
return __chunk_2.call.apply(void 0, [retry, maxTries, delayLength, worker].concat(args)); | ||
return __chunk_1.call.apply(void 0, [retry, maxTries, delayLength, worker].concat(args)); | ||
} | ||
@@ -449,26 +448,26 @@ function debounce(delayLength, pattern, worker) { | ||
return __chunk_2.fork.apply(void 0, [debounceHelper, delayLength, pattern, worker].concat(args)); | ||
return __chunk_1.fork.apply(void 0, [debounceHelper, delayLength, pattern, worker].concat(args)); | ||
} | ||
exports.effectTypes = __chunk_2.effectTypes; | ||
exports.take = __chunk_2.take; | ||
exports.takeMaybe = __chunk_2.takeMaybe; | ||
exports.put = __chunk_2.put; | ||
exports.putResolve = __chunk_2.putResolve; | ||
exports.all = __chunk_2.all; | ||
exports.race = __chunk_2.race; | ||
exports.call = __chunk_2.call; | ||
exports.apply = __chunk_2.apply; | ||
exports.cps = __chunk_2.cps; | ||
exports.fork = __chunk_2.fork; | ||
exports.spawn = __chunk_2.spawn; | ||
exports.join = __chunk_2.join; | ||
exports.cancel = __chunk_2.cancel; | ||
exports.select = __chunk_2.select; | ||
exports.actionChannel = __chunk_2.actionChannel; | ||
exports.cancelled = __chunk_2.cancelled; | ||
exports.flush = __chunk_2.flush; | ||
exports.getContext = __chunk_2.getContext; | ||
exports.setContext = __chunk_2.setContext; | ||
exports.delay = __chunk_2.delay; | ||
exports.effectTypes = __chunk_1.effectTypes; | ||
exports.take = __chunk_1.take; | ||
exports.takeMaybe = __chunk_1.takeMaybe; | ||
exports.put = __chunk_1.put; | ||
exports.putResolve = __chunk_1.putResolve; | ||
exports.all = __chunk_1.all; | ||
exports.race = __chunk_1.race; | ||
exports.call = __chunk_1.call; | ||
exports.apply = __chunk_1.apply; | ||
exports.cps = __chunk_1.cps; | ||
exports.fork = __chunk_1.fork; | ||
exports.spawn = __chunk_1.spawn; | ||
exports.join = __chunk_1.join; | ||
exports.cancel = __chunk_1.cancel; | ||
exports.select = __chunk_1.select; | ||
exports.actionChannel = __chunk_1.actionChannel; | ||
exports.cancelled = __chunk_1.cancelled; | ||
exports.flush = __chunk_1.flush; | ||
exports.getContext = __chunk_1.getContext; | ||
exports.setContext = __chunk_1.setContext; | ||
exports.delay = __chunk_1.delay; | ||
exports.debounce = debounce; | ||
@@ -475,0 +474,0 @@ exports.retry = retry$1; |
@@ -1,1 +0,1 @@ | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.ReduxSaga={})}(this,function(n){"use strict";var t=function(n){return"@@redux-saga/"+n},h=t("CANCEL_PROMISE"),e=t("CHANNEL_END"),M=t("IO"),f=t("MATCH"),r=t("MULTICAST"),o=t("SAGA_ACTION"),I=t("SELF_CANCELLATION"),g=t("TASK"),y=t("TASK_CANCEL"),P=t("TERMINATE"),a=t("LOCATION");var U=function(n){return null==n},D=function(n){return null!=n},A=function(n){return"function"==typeof n},u=function(n){return"string"==typeof n},K=Array.isArray,z=function(n){return n&&A(n.then)},F=function(n){return n&&A(n.next)&&A(n.throw)},c=function n(t){return t&&(u(t)||s(t)||A(t)||K(t)&&t.every(n))},i=function(n){return n&&A(n.take)&&A(n.close)},l=function(n){return A(n)&&n.hasOwnProperty("toString")},s=function(n){return!!n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype},d=function(n){return i(n)&&n[r]};function G(){return(G=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r])}return n}).apply(this,arguments)}var v=function(n){return function(){return n}}(!0),H=function(){},p=function(n){return n},E=Object.prototype.hasOwnProperty;var X=function(t,e){G(t,e),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(e).forEach(function(n){t[n]=e[n]})};function b(n,t){var e=n.indexOf(t);e<0||n.splice(e,1)}var J={from:function(n){var t,e,r=Array(n.length);for(var o in n)e=o,D(t=n)&&E.call(t,e)&&(r[o]=n[o]);return r}};function S(n){var t=!1;return function(){t||(t=!0,n())}}function m(n){return void 0===n&&(n=0),function(){return++n}}var C=m(),_=function(n){throw n},x=function(n){return{value:n,done:!0}};function B(n,t,e){void 0===t&&(t=_),void 0===e&&(e="iterator");var r={meta:{name:e},next:n,throw:t,return:x,isSagaIterator:!0};return"undefined"!=typeof Symbol&&(r[Symbol.iterator]=function(){return r}),r}function T(n,t,e){void 0===e&&(e=""),"undefined"==typeof window?console.log("redux-saga "+n+": "+t+"\n"+(e&&e.stack||e)):console[n](t,e)}var k=function(t){return function(n){return t(Object.defineProperty(n,o,{value:!0}))}},Q=function(n){return n===P},V=function(n){return n===y},W=function(n){return Q(n)||V(n)};function Y(r,o){var a,n=Object.keys(r),u=n.length,c=0,i={},t={};return n.forEach(function(e){var n=function(n,t){a||(t||W(n)?(o.cancel(),o(n,t)):(i[e]=n,++c===u&&(a=!0,K(r)?o(J.from(G({},i,{length:u}))):o(i))))};n.cancel=H,t[e]=n}),o.cancel=function(){a||(a=!0,n.forEach(function(n){return t[n].cancel()}))},t}var O={isEmpty:v,put:H,take:H};function q(e,r){void 0===e&&(e=10);var o=Array(e),a=0,u=0,c=0,i=function(n){o[u]=n,u=(u+1)%e,a++},t=function(){if(0!=a){var n=o[c];return o[c]=null,a--,c=(c+1)%e,n}},f=function(){for(var n=[];a;)n.push(t());return n};return{isEmpty:function(){return 0==a},put:function(n){var t;if(a<e)i(n);else switch(r){case 1:throw Error("Channel's Buffer overflow!");case 3:o[u]=n,c=u=(u+1)%e;break;case 4:t=2*e,o=f(),u=a=o.length,c=0,e=o.length=t,i(n)}},take:t,flush:f}}var N=function(){return O},j=function(n){return q(n,3)},w=function(n){return q(n,4)},L=Object.freeze({none:N,fixed:function(n){return q(n,1)},dropping:function(n){return q(n,2)},sliding:j,expanding:w}),R=[],Z=0;function $(n){try{tn(),n()}finally{en()}}function nn(n){R.push(n),Z||(tn(),rn())}function tn(){Z++}function en(){Z--}function rn(){var n;for(en();!Z&&void 0!==(n=R.shift());)$(n)}var on=function(n){return function(t){return n.some(function(n){return ln(n)(t)})}},an=function(t){return function(n){return t(n)}},un=function(t){return function(n){return n.type===t+""}},cn=function(t){return function(n){return n.type===t}},fn=function(){return v};function ln(n){var t="*"===n?fn:u(n)?un:K(n)?on:l(n)?un:A(n)?an:s(n)?cn:null;if(null===t)throw Error("invalid pattern: "+n);return t(n)}var sn,dn={type:e},vn=function(n){return n&&n.type===e};function pn(t){void 0===t&&(t=w());var r=!1,o=[];return{take:function(n){r&&t.isEmpty()?n(dn):t.isEmpty()?(o.push(n),n.cancel=function(){b(o,n)}):n(t.take())},put:function(n){if(!r){if(0===o.length)return t.put(n);o.shift()(n)}},flush:function(n){r&&t.isEmpty()?n(dn):n(t.flush())},close:function(){if(!r){r=!0;var n=o;o=[];for(var t=0,e=n.length;t<e;t++)(0,n[t])(dn)}}}}function hn(){var n,a=!1,u=[],c=u,e=function(){c===u&&(c=u.slice())},i=function(){a=!0;var n=u=c;c=[],n.forEach(function(n){n(dn)})};return(n={})[r]=!0,n.put=function(n){if(!a)if(vn(n))i();else for(var t=u=c,e=0,r=t.length;e<r;e++){var o=t[e];o[f](n)&&(o.cancel(),o(n))}},n.take=function(n,t){void 0===t&&(t=fn),a?n(dn):(n[f]=t,e(),c.push(n),n.cancel=S(function(){e(),b(c,n)}))},n.close=i,n}function gn(){var n=hn(),t=n.put;return n.put=function(n){n[o]?t(n):nn(function(){t(n)})},n}sn="undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof module?module:Function("return this")();"function"==typeof(En=sn.Symbol)?En.observable?yn=En.observable:(yn=En("observable"),En.observable=yn):yn="@@observable";var yn,En,bn=function(){return Math.random().toString(36).substring(7).split("").join(".")};bn(),bn();var Sn="TAKE",An="PUT",mn="ALL",Cn="RACE",_n="CALL",xn="CPS",Tn="FORK",kn="JOIN",On="CANCEL",qn="SELECT",Nn="ACTION_CHANNEL",jn="CANCELLED",wn="FLUSH",Ln="GET_CONTEXT",Rn="SET_CONTEXT",Mn=Object.freeze({TAKE:Sn,PUT:An,ALL:mn,RACE:Cn,CALL:_n,CPS:xn,FORK:Tn,JOIN:kn,CANCEL:On,SELECT:qn,ACTION_CHANNEL:Nn,CANCELLED:jn,FLUSH:wn,GET_CONTEXT:Ln,SET_CONTEXT:Rn});function In(n,t){return n+"?"+t}function Pn(n){return n[a]}function Un(n){var t=n.name,e=n.location;return e?t+" "+In(e.fileName,e.lineNumber):t}var Dn=function(n,t){var e;return(e=[]).concat.apply(e,t.map(n))};function Kn(n){var t,e,r,o=n[0],a=n.slice(1),u=o.effect?(t=Pn(o.effect))?t.code+" "+In(t.fileName,t.lineNumber):"":null;return["The above error occurred in task "+Un(o.meta)+(u?" \n when executing effect "+u:"")].concat(a.map(function(n){return" created by "+Un(n.meta)}),[(e=n,r=Dn(function(n){return n.cancelledTasks},e),r.length?["Tasks cancelled due to error:"].concat(r).join("\n"):"")]).join("\n")}function zn(n){return{name:n.name||"anonymous",location:Pn(n)}}function Fn(_,r,n,o,x,t){var T=Object.create(n),c=_.finalizeRunEffect(function(n,t,e){if(z(n))j(n,e);else if(F(n))w(n,t,x,e);else if(n&&n[M]){var r=n.type,o=n.payload;r===Sn?function(n,t){var e=n.channel,r=void 0===e?_.stdChannel:e,o=n.pattern,a=n.maybe,u=function(n){n instanceof Error?t(n,!0):!vn(n)||a?t(n):t(P)};try{r.take(u,D(o)?ln(o):null)}catch(n){return t(n,!0)}t.cancel=u.cancel}(o,e):r===An?(S=e,A=(b=o).channel,m=b.action,C=b.resolve,nn(function(){var n;try{n=(A?A.put:_.dispatch)(m)}catch(n){return void S(n,!0)}C&&z(n)?j(n,S):S(n)})):r===mn?function(t,e,n){var r=Object.keys(t);if(0===r.length)return n(K(t)?[]:{});var o=Y(t,n);r.forEach(function(n){return N(t[n],e,n,o[n])})}(o,t,e):r===Cn?(p=t,h=e,E={},(y=Object.keys(v=o)).forEach(function(o){var n=function(n,t){if(!g)if(t||W(n))h.cancel(),h(n,t);else{var e;h.cancel(),g=!0;var r=((e={})[o]=n,e);h(K(v)?J.from(G({},r,{length:y.length})):r)}};n.cancel=H,E[o]=n}),h.cancel=function(){g||(g=!0,y.forEach(function(n){return E[n].cancel()}))},y.forEach(function(n){g||N(v[n],p,n,E[n])})):r===_n?function(n,t,e){var r=n.context,o=n.fn,a=n.args;try{var u=o.apply(r,a);if(z(u))return j(u,e);if(F(u))return w(u,t,zn(o),e);e(u)}catch(n){e(n,!0)}}(o,t,e):r===xn?function(n,e){var t=n.context,r=n.fn,o=n.args;try{var a=function(n,t){return U(n)?e(t):e(n,!0)};r.apply(t,o.concat(a)),a.cancel&&(e.cancel=function(){return a.cancel()})}catch(n){e(n,!0)}}(o,e):r===Tn?function(n,t,e){var r=n.fn,o=n.detached,a=function(n){var t=n.context,e=n.fn,r=n.args;try{var o=e.apply(t,r);return F(o)?o:B(function(n){return void 0===n&&(n=o),{value:n,done:!z(n)}})}catch(n){return B(function(){throw n})}}({context:n.context,fn:r,args:n.args}),u=(c=a,i=r,c.isSagaIterator?{name:c.meta.name}:zn(i));var c,i;try{tn();var f=Fn(_,a,T,t,u,o?null:H);o?e(f):f._isRunning?(q.addTask(f),e(f)):f._error?q.abort(f._error):e(f)}finally{rn()}}(o,t,e):r===kn?function(n,t){if(K(n)){if(0===n.length)return t([]);var e=Y(n,t);n.forEach(function(n,t){L(n,e[t])})}else L(n,t)}(o,e):r===On?function(n,t){n===I?R(k):K(n)?n.forEach(R):R(n);t()}(o,e):r===qn?function(n,t){var e=n.selector,r=n.args;try{var o=e.apply(void 0,[_.getState()].concat(r));t(o)}catch(n){t(n,!0)}}(o,e):r===Nn?(c=e,i=(u=o).pattern,f=pn(u.buffer),l=ln(i),s=function n(t){vn(t)||_.stdChannel.take(n,l),f.put(t)},d=f.close,f.close=function(){s.cancel(),d()},_.stdChannel.take(s,l),c(f)):r===wn?o.flush(e):r===jn?e(!!O._isCancelled):r===Ln?e(T[o]):r===Rn?(a=e,X(T,o),a()):e(n)}else e(n);var a;var u,c,i,f,l,s,d;var v,p,h,g,y,E;var b,S,A,m,C}),i=null,a=[];v.cancel=H;var e,u,f,l,s,k=(e=o,u=x,f=t,(l={})[g]=!0,l.id=e,l.meta=u,l._deferredEnd=null,l.toPromise=function(){if(s._deferredEnd)return s._deferredEnd.promise;var e,n=((e={}).promise=new Promise(function(n,t){e.resolve=n,e.reject=t}),e);return s._deferredEnd=n,s._isRunning||(s._isAborted?n.reject(s._error):n.resolve(s._result)),n.promise},l.cont=f,l.joiners=[],l.cancel=d,l._isRunning=!0,l._isCancelled=!1,l._isAborted=!1,l._result=void 0,l._error=void 0,l.isRunning=function(){return s._isRunning},l.isCancelled=function(){return s._isCancelled},l.isAborted=function(){return s._isAborted},l.result=function(){return s._result},l.error=function(){return s._error},l.setContext=function(n){X(T,n)},s=l),O={meta:x,cancel:function(){O._isRunning&&!O._isCancelled&&(O._isCancelled=!0,v(y))},_isRunning:!0,_isCancelled:!1},q=function(r,t,o){var a,u=[],c=!1;function i(n){t(),e(),o(n,!0)}function n(e){u.push(e),e.cont=function(n,t){c||(b(u,e),e.cont=H,t?i(n):(e===r&&(a=n),u.length||(c=!0,o(a))))}}function e(){c||(c=!0,u.forEach(function(n){n.cont=H,n.cancel()}),u=[])}return n(r),{addTask:n,cancelAll:e,abort:i,getTasks:function(){return u},getTaskNames:function(){return u.map(function(n){return n.meta.name})}}}(O,function(){a.push.apply(a,q.getTaskNames())},p);function d(){k._isRunning&&!k._isCancelled&&(k._isCancelled=!0,q.cancelAll(),p(y))}return t&&(t.cancel=d),v(),k;function v(n,t){if(!O._isRunning)throw Error("Trying to resume an already finished generator");try{var e;(e=t?r.throw(n):V(n)?(O._isCancelled=!0,v.cancel(),A(r.return)?r.return(y):{done:!0,value:y}):Q(n)?A(r.return)?r.return():{done:!0}:r.next(n)).done?(O._isRunning=!1,O.cont(e.value)):N(e.value,o,"",v)}catch(n){O._isCancelled&&_.logError(n),O._isRunning=!1,O.cont(n,!0)}}function p(t,e){var n,r;k._isRunning=!1,e?(r={meta:x,effect:i,cancelledTasks:a},"object"==typeof(n=t)&&(void 0===n.sagaStack&&Object.defineProperty(n,"sagaStack",{value:[],writable:!0,enumerable:!1}),n.sagaStack.push(r)),k.cont||(t&&t.sagaStack&&(t.sagaStack=Kn(t.sagaStack)),_.onError?_.onError(t):_.logError(t)),k._error=t,k._isAborted=!0,k._deferredEnd&&k._deferredEnd.reject(t)):(k._result=t,k._deferredEnd&&k._deferredEnd.resolve(t)),k.cont&&k.cont(t,e),k.joiners.forEach(function(n){return n.cb(t,e)}),k.joiners=null}function N(e,n,t,r){void 0===t&&(t="");var o,a=C();function u(n,t){o||(o=!0,r.cancel=H,_.sagaMonitor&&(t?_.sagaMonitor.effectRejected(a,n):_.sagaMonitor.effectResolved(a,n)),t&&(i=e),r(n,t))}_.sagaMonitor&&_.sagaMonitor.effectTriggered({effectId:a,parentEffectId:n,label:t,effect:e}),u.cancel=H,r.cancel=function(){if(!o){o=!0;try{u.cancel()}catch(n){_.logError(n)}u.cancel=H,_.sagaMonitor&&_.sagaMonitor.effectCancelled(a)}},c(e,a,u)}function j(n,t){var e=n[h];A(e)?t.cancel=e:A(n.abort)&&(t.cancel=function(){return n.abort()}),n.then(t,function(n){return t(n,!0)})}function w(n,t,e,r){Fn(_,n,T,t,e,r)}function L(n,t){if(n.isRunning()){var e={task:k,cb:t};t.cancel=function(){return b(n.joiners,e)},n.joiners.push(e)}else n.isAborted()?t(n.error(),!0):t(n.result())}function R(n){n.isRunning()&&n.cancel()}}function Gn(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a=t.apply(void 0,r),u=n.channel,c=void 0===u?gn():u,i=n.dispatch,f=n.getState,l=n.context,s=void 0===l?{}:l,d=n.sagaMonitor,v=n.logger,p=n.effectMiddlewares,h=n.onError,g=C();d&&(d.rootSagaStarted=d.rootSagaStarted||H,d.effectTriggered=d.effectTriggered||H,d.effectResolved=d.effectResolved||H,d.effectRejected=d.effectRejected||H,d.effectCancelled=d.effectCancelled||H,d.actionDispatched=d.actionDispatched||H,d.rootSagaStarted({effectId:g,saga:t,args:r}));var y=v||T,E=p&&function(){for(var n=arguments.length,t=Array(n),e=0;e<n;e++)t[e]=arguments[e];return 0===t.length?function(n){return n}:1===t.length?t[0]:t.reduce(function(n,t){return function(){return n(t.apply(void 0,arguments))}})}.apply(void 0,p),b={stdChannel:c,dispatch:k(i),getState:f,sagaMonitor:d,logError:function(n){y("error",n),n&&n.sagaStack&&y("error",n.sagaStack)},onError:h,finalizeRunEffect:function(r){return A(E)?function(n,t,e){return E(function(n){return r(n,t,e)})(n)}:r}};try{tn();var S=Fn(b,a,s,g,zn(t),null);return d&&d.effectResolved(g,S),S}finally{rn()}}function Hn(t,e){var r;void 0===e&&(e=!0);var n=new Promise(function(n){r=setTimeout(n,t,e)});return n[h]=function(){clearTimeout(r)},n}var Xn=function(n,t){var e;return(e={})[M]=!0,e.type=n,e.payload=t,e},Jn=function(n){return Xn(Tn,G({},n.payload,{detached:!0}))};function Bn(n,t){if(void 0===n&&(n="*"),c(n))return Xn(Sn,{pattern:n});if(d(n)&&D(t)&&c(t))return Xn(Sn,{channel:n,pattern:t});if(i(n))return Xn(Sn,{channel:n});throw Error("take(patternOrChannel): argument "+n+" is not valid channel or a valid pattern")}function Qn(n,t){return U(t)&&(t=n,n=null),Xn(An,{channel:n,action:t})}function Vn(n){return Xn(Cn,n)}function Wn(n,t){var e,r=null;return A(n)?e=n:(e=K(n)?(r=n[0],n[1]):(r=n.context,n.fn),r&&u(e)&&A(r[e])&&(e=r[e])),{context:r,fn:e,args:t}}function Yn(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return Xn(_n,Wn(n,e))}function Zn(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return Xn(Tn,Wn(n,e))}function $n(n){return void 0===n&&(n=I),Xn(On,n)}function nt(n,t){return Xn(Nn,{pattern:n,buffer:t})}var tt=Yn.bind(null,Hn),et=function(n){return{done:!0,value:n}},rt={};function ot(n){return i(n)?"channel":l(n)?n+"":A(n)?n.name:n+""}function at(r,n,t){var o,a,u,c=n;function e(n,t){if(c===rt)return et(n);if(t&&!a)throw c=rt,t;o&&o(n);var e=t?r[a](t):r[c]();return u=e.effect,o=e.stateUpdater,a=e.errorState,(c=e.nextState)===rt?et(n):u}return B(e,function(n){return e(null,n)},t)}function ut(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a,u={done:!1,value:Bn(n)},c=function(n){return a=n};return at({q1:function(){return{nextState:"q2",effect:u,stateUpdater:c}},q2:function(){return{nextState:"q1",effect:(n=a,{done:!1,value:Zn.apply(void 0,[t].concat(r,[n]))})};var n}},"q1","takeEvery("+ot(n)+", "+t.name+")")}function ct(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a,u,c={done:!1,value:Bn(n)},i=function(n){return{done:!1,value:Zn.apply(void 0,[t].concat(r,[n]))}},f=function(n){return a=n},l=function(n){return u=n};return at({q1:function(){return{nextState:"q2",effect:c,stateUpdater:l}},q2:function(){return a?{nextState:"q3",effect:(n=a,{done:!1,value:$n(n)})}:{nextState:"q1",effect:i(u),stateUpdater:f};var n},q3:function(){return{nextState:"q1",effect:i(u),stateUpdater:f}}},"q1","takeLatest("+ot(n)+", "+t.name+")")}function it(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a,u={done:!1,value:Bn(n)},c=function(n){return a=n};return at({q1:function(){return{nextState:"q2",effect:u,stateUpdater:c}},q2:function(){return{nextState:"q1",effect:(n=a,{done:!1,value:Yn.apply(void 0,[t].concat(r,[n]))})};var n}},"q1","takeLeading("+ot(n)+", "+t.name+")")}function ft(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];var u,c,i={done:!1,value:nt(t,j(1))},f={done:!1,value:tt(n)},l=function(n){return u=n},s=function(n){return c=n};return at({q1:function(){return{nextState:"q2",effect:i,stateUpdater:s}},q2:function(){return{nextState:"q3",effect:{done:!1,value:Bn(c)},stateUpdater:l}},q3:function(){return{nextState:"q4",effect:(n=u,{done:!1,value:Zn.apply(void 0,[e].concat(o,[n]))})};var n},q4:function(){return{nextState:"q2",effect:f}}},"q1","throttle("+ot(t)+", "+e.name+")")}function lt(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];var u,c,i={done:!1,value:Bn(t)},f={done:!1,value:Vn({action:Bn(t),debounce:tt(n)})},l=function(n){return u=n},s=function(n){return c=n};return at({q1:function(){return{nextState:"q2",effect:i,stateUpdater:l}},q2:function(){return{nextState:"q3",effect:f,stateUpdater:s}},q3:function(){return c.debounce?{nextState:"q1",effect:(t=u,{done:!1,value:Zn.apply(void 0,[e].concat(o,[t]))})}:{nextState:"q2",effect:(n=c.action,{done:!1,value:n}),stateUpdater:l};var n,t}},"q1","debounce("+ot(t)+", "+e.name+")")}var st=Object.freeze({effectTypes:Mn,take:Bn,takeMaybe:function(){var n=Bn.apply(void 0,arguments);return n.payload.maybe=!0,n},put:Qn,putResolve:function(){var n=Qn.apply(void 0,arguments);return n.payload.resolve=!0,n},all:function(n){return Xn(mn,n)},race:Vn,call:Yn,apply:function(n,t,e){return void 0===e&&(e=[]),Xn(_n,Wn([n,t],e))},cps:function(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return Xn(xn,Wn(n,e))},fork:Zn,spawn:function(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return Jn(Zn.apply(void 0,[n].concat(e)))},join:function(n){return Xn(kn,n)},cancel:$n,select:function(n){void 0===n&&(n=p);for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return Xn(qn,{selector:n,args:e})},actionChannel:nt,cancelled:function(){return Xn(jn,{})},flush:function(n){return Xn(wn,n)},getContext:function(n){return Xn(Ln,n)},setContext:function(n){return Xn(Rn,n)},delay:tt,debounce:function(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];return Zn.apply(void 0,[lt,n,t,e].concat(o))},retry:function(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];return Yn.apply(void 0,[function(n,t,e){for(var r=n,o=arguments.length,a=Array(3<o?o-3:0),u=3;u<o;u++)a[u-3]=arguments[u];var c={done:!1,value:Yn.apply(void 0,[e].concat(a))},i={done:!1,value:tt(t)};return at({q1:function(){return{nextState:"q2",effect:c,errorState:"q10"}},q2:function(){return{nextState:rt}},q10:function(n){if((r-=1)<=0)throw n;return{nextState:"q1",effect:i}}},"q1","retry("+e.name+")")},n,t,e].concat(o))},takeEvery:function(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];return Zn.apply(void 0,[ut,n,t].concat(r))},takeLatest:function(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];return Zn.apply(void 0,[ct,n,t].concat(r))},takeLeading:function(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];return Zn.apply(void 0,[it,n,t].concat(r))},throttle:function(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];return Zn.apply(void 0,[ft,n,t,e].concat(o))}}),dt=Object.freeze({SAGA_ACTION:o,TASK:g,createMockTask:function(){var n,t,e,r=!0;return(n={})[g]=!0,n.isRunning=function(){return r},n.result=function(){return t},n.error=function(){return e},n.setRunning=function(n){return r=n},n.setResult=function(n){return t=n},n.setError=function(n){return e=n},n},cloneableGenerator:function a(u){return function(){for(var n=arguments.length,e=Array(n),t=0;t<n;t++)e[t]=arguments[t];var r=[],o=u.apply(void 0,e);return{next:function(n){return r.push(n),o.next(n)},clone:function(){var t=a(u).apply(void 0,e);return r.forEach(function(n){return t.next(n)}),t},return:function(n){return o.return(n)},throw:function(n){return o.throw(n)}}}}});n.effects=st,n.utils=dt,n.default=function(n){void 0===n&&(n={});var o,t=n.context,a=void 0===t?{}:t,u=function(n,t){if(null==n)return{};var e,r,o={},a=Object.keys(n);for(r=0;r<a.length;r++)t.indexOf(e=a[r])<0&&(o[e]=n[e]);return o}(n,["context"]),c=u.sagaMonitor,i=u.logger,f=u.onError,l=u.effectMiddlewares;function e(n){var t=n.getState,e=n.dispatch,r=gn();return r.put=(u.emitter||p)(r.put),o=Gn.bind(null,{context:a,channel:r,dispatch:e,getState:t,sagaMonitor:c,logger:i,onError:f,effectMiddlewares:l}),function(e){return function(n){c&&c.actionDispatched&&c.actionDispatched(n);var t=e(n);return r.put(n),t}}}return e.run=function(){return o.apply(void 0,arguments)},e.setContext=function(n){X(a,n)},e},n.buffers=L,n.CANCEL=h,n.SAGA_LOCATION=a,n.runSaga=Gn,n.END=dn,n.isEnd=vn,n.eventChannel=function(n,t){void 0===t&&(t=N());var e,r=!1,o=pn(t),a=function(){r||(r=!0,A(e)&&e(),o.close())};return e=S(e=n(function(n){vn(n)?a():o.put(n)})),r&&e(),{take:o.take,flush:o.flush,close:a}},n.channel=pn,n.multicastChannel=hn,n.stdChannel=gn,n.detach=Jn,Object.defineProperty(n,"__esModule",{value:!0})}); | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.ReduxSaga={})}(this,function(n){"use strict";var t=function(n){return"@@redux-saga/"+n},o=t("CANCEL_PROMISE"),e=t("CHANNEL_END"),d=t("IO"),i=t("MATCH"),r=t("MULTICAST"),a=t("SAGA_ACTION"),c=t("SELF_CANCELLATION"),g=t("TASK"),E=t("TASK_CANCEL"),f=t("TERMINATE"),u=t("LOCATION");function l(){return(l=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r])}return n}).apply(this,arguments)}var s=function(n){return null==n},v=function(n){return null!=n},p=function(n){return"function"==typeof n},h=function(n){return"string"==typeof n},y=Array.isArray,S=function(n){return n&&p(n.then)},A=function(n){return n&&p(n.next)&&p(n.throw)},b=function n(t){return t&&(h(t)||x(t)||p(t)||y(t)&&t.every(n))},m=function(n){return n&&p(n.take)&&p(n.close)},C=function(n){return p(n)&&n.hasOwnProperty("toString")},x=function(n){return!!n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype},T=function(n){return m(n)&&n[r]},k=function(n){return function(){return n}}(!0),q=function(){},O=function(n){return n},L=function(t,e){l(t,e),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(e).forEach(function(n){t[n]=e[n]})};function N(n,t){var e=n.indexOf(t);e<0||n.splice(e,1)}function j(n){var t=!1;return function(){t||(t=!0,n())}}var w=function(n){throw n},R=function(n){return{value:n,done:!0}};function M(n,t,e){void 0===t&&(t=w),void 0===e&&(e="iterator");var r={meta:{name:e},next:n,throw:t,return:R,isSagaIterator:!0};return"undefined"!=typeof Symbol&&(r[Symbol.iterator]=function(){return r}),r}function P(n,t){var e=t.sagaStack;console.error(n),console.error(e)}var U=function(n){return Array.apply(null,Array(n))},I=function(t){return function(n){return t(Object.defineProperty(n,a,{value:!0}))}},_=function(n){return n===f},D=function(n){return n===E},F=function(n){return _(n)||D(n)};function H(n,r){var o,t=Object.keys(n),a=t.length,c=0,u=y(n)?U(a):{},f={};return t.forEach(function(e){var n=function(n,t){o||(t||F(n)?(r.cancel(),r(n,t)):(u[e]=n,++c===a&&(o=!0,r(u))))};n.cancel=q,f[e]=n}),r.cancel=function(){o||(o=!0,t.forEach(function(n){return f[n].cancel()}))},f}function K(n){return{name:n.name||"anonymous",location:z(n)}}function z(n){return n[u]}var G={isEmpty:k,put:q,take:q};function X(e,r){void 0===e&&(e=10);var o=Array(e),a=0,c=0,u=0,f=function(n){o[c]=n,c=(c+1)%e,a++},t=function(){if(0!=a){var n=o[u];return o[u]=null,a--,u=(u+1)%e,n}},i=function(){for(var n=[];a;)n.push(t());return n};return{isEmpty:function(){return 0==a},put:function(n){var t;if(a<e)f(n);else switch(r){case 1:throw Error("Channel's Buffer overflow!");case 3:o[c]=n,u=c=(c+1)%e;break;case 4:t=2*e,o=i(),c=a=o.length,u=0,e=o.length=t,f(n)}},take:t,flush:i}}var J=function(){return G},B=function(n){return X(n,3)},Q=function(n){return X(n,4)},V=Object.freeze({none:J,fixed:function(n){return X(n,1)},dropping:function(n){return X(n,2)},sliding:B,expanding:Q}),W=[],Y=0;function Z(n){try{tn(),n()}finally{en()}}function $(n){W.push(n),Y||(tn(),rn())}function nn(n){try{return tn(),n()}finally{rn()}}function tn(){Y++}function en(){Y--}function rn(){var n;for(en();!Y&&void 0!==(n=W.shift());)Z(n)}var on=function(n){return function(t){return n.some(function(n){return ln(n)(t)})}},an=function(t){return function(n){return t(n)}},cn=function(t){return function(n){return n.type===t+""}},un=function(t){return function(n){return n.type===t}},fn=function(){return k};function ln(n){var t="*"===n?fn:h(n)?cn:y(n)?on:C(n)?cn:p(n)?an:x(n)?un:null;if(null===t)throw Error("invalid pattern: "+n);return t(n)}var sn,vn={type:e},dn=function(n){return n&&n.type===e};function pn(t){void 0===t&&(t=Q());var r=!1,o=[];return{take:function(n){r&&t.isEmpty()?n(vn):t.isEmpty()?(o.push(n),n.cancel=function(){N(o,n)}):n(t.take())},put:function(n){if(!r){if(0===o.length)return t.put(n);o.shift()(n)}},flush:function(n){r&&t.isEmpty()?n(vn):n(t.flush())},close:function(){if(!r){r=!0;var n=o;o=[];for(var t=0,e=n.length;t<e;t++)(0,n[t])(vn)}}}}function hn(){var n,a=!1,c=[],u=c,e=function(){u===c&&(u=c.slice())},f=function(){a=!0;var n=c=u;u=[],n.forEach(function(n){n(vn)})};return(n={})[r]=!0,n.put=function(n){if(!a)if(dn(n))f();else for(var t=c=u,e=0,r=t.length;e<r;e++){var o=t[e];o[i](n)&&(o.cancel(),o(n))}},n.take=function(n,t){void 0===t&&(t=fn),a?n(vn):(n[i]=t,e(),u.push(n),n.cancel=j(function(){e(),N(u,n)}))},n.close=f,n}function yn(){var n=hn(),t=n.put;return n.put=function(n){n[a]?t(n):$(function(){t(n)})},n}sn="undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof module?module:Function("return this")();"function"==typeof(En=sn.Symbol)?En.observable?gn=En.observable:(gn=En("observable"),En.observable=gn):gn="@@observable";var gn,En,Sn=function(){return Math.random().toString(36).substring(7).split("").join(".")};Sn(),Sn();var An=0,bn=1,mn=2,Cn=3,xn="TAKE",Tn="RACE",kn="CALL",qn="FORK",On="JOIN",Ln="CANCEL",Nn="SELECT",jn="ACTION_CHANNEL",wn="CANCELLED",Rn="FLUSH",Mn="GET_CONTEXT",Pn="SET_CONTEXT",Un=Object.freeze({TAKE:xn,PUT:"PUT",ALL:"ALL",RACE:Tn,CALL:kn,CPS:"CPS",FORK:qn,JOIN:On,CANCEL:Ln,SELECT:Nn,ACTION_CHANNEL:jn,CANCELLED:wn,FLUSH:Rn,GET_CONTEXT:Mn,SET_CONTEXT:Pn});function In(n,t){var e=n[o];p(e)&&(t.cancel=e),n.then(t,function(n){t(n,!0)})}var _n,Dn=0,Fn=function(){return++Dn};function Hn(n){n.isRunning()&&n.cancel()}var Kn=((_n={})[xn]=function(n,t,e){var r=t.channel,o=void 0===r?n.channel:r,a=t.pattern,c=t.maybe,u=function(n){n instanceof Error?e(n,!0):!dn(n)||c?e(n):e(f)};try{o.take(u,v(a)?ln(a):null)}catch(n){return void e(n,!0)}e.cancel=u.cancel},_n.PUT=function(t,n,e){var r=n.channel,o=n.action,a=n.resolve;$(function(){var n;try{n=(r?r.put:t.dispatch)(o)}catch(n){return void e(n,!0)}a&&S(n)?In(n,e):e(n)})},_n.ALL=function(n,t,e,r){var o=r.digestEffect,a=Dn,c=Object.keys(t);if(0!==c.length){var u=H(t,e);c.forEach(function(n){o(t[n],a,u[n],n)})}else e(y(t)?[]:{})},_n[Tn]=function(n,t,r,e){var o=e.digestEffect,a=Dn,c=Object.keys(t),u=y(t)?U(c.length):{},f={},i=!1;c.forEach(function(e){var n=function(n,t){i||(t||F(n)?(r.cancel(),r(n,t)):(r.cancel(),i=!0,u[e]=n,r(u)))};n.cancel=q,f[e]=n}),r.cancel=function(){i||(i=!0,c.forEach(function(n){return f[n].cancel()}))},c.forEach(function(n){i||o(t[n],a,f[n],n)})},_n[kn]=function(n,t,e,r){var o=t.context,a=t.fn,c=t.args,u=r.task;try{var f=a.apply(o,c);if(S(f))return void In(f,e);if(A(f))return void Zn(n,f,u.context,Dn,K(a),!1,e);e(f)}catch(n){e(n,!0)}},_n.CPS=function(n,t,e){var r=t.context,o=t.fn,a=t.args;try{var c=function(n,t){s(n)?e(t):e(n,!0)};o.apply(r,a.concat(c)),c.cancel&&(e.cancel=c.cancel)}catch(n){e(n,!0)}},_n[qn]=function(t,n,e,r){var o,a,c=n.fn,u=n.detached,f=r.task,i=function(n){var t=n.context,e=n.fn,r=n.args;try{var o=e.apply(t,r);return A(o)?o:M(function(n){return void 0===n&&(n=o),{value:n,done:!S(n)}})}catch(n){return M(function(){throw n})}}({context:n.context,fn:c,args:n.args}),l=(a=c,(o=i).isSagaIterator?{name:o.meta.name}:K(a));nn(function(){var n=Zn(t,i,f.context,Dn,l,u,q);u?e(n):n.isRunning()?(f.queue.addTask(n),e(n)):n.isAborted()?f.queue.abort(n.error()):e(n)})},_n[On]=function(n,t,e,r){var o=r.task,a=function(n,t){if(n.isRunning()){var e={task:o,cb:t};t.cancel=function(){N(n.joiners,e)},n.joiners.push(e)}else n.isAborted()?t(n.error(),!0):t(n.result())};if(y(t)){if(0===t.length)return void e([]);var c=H(t,e);t.forEach(function(n,t){a(n,c[t])})}else a(t,e)},_n[Ln]=function(n,t,e,r){t===c?Hn(r.task):y(t)?t.forEach(Hn):Hn(t),e()},_n[Nn]=function(n,t,e){var r=t.selector,o=t.args;try{e(r.apply(void 0,[n.getState()].concat(o)))}catch(n){e(n,!0)}},_n[jn]=function(e,n,t){var r=n.pattern,o=pn(n.buffer),a=ln(r),c=function n(t){dn(t)||e.channel.take(n,a),o.put(t)},u=o.close;o.close=function(){c.cancel(),u()},e.channel.take(c,a),t(o)},_n[wn]=function(n,t,e,r){e(r.task.isCancelled())},_n[Rn]=function(n,t,e){t.flush(e)},_n[Mn]=function(n,t,e,r){e(r.task.context[t])},_n[Pn]=function(n,t,e,r){L(r.task.context,t),e()},_n);function zn(n,t){return n+"?"+t}function Gn(n){var t=n.name,e=n.location;return e?t+" "+zn(e.fileName,e.lineNumber):t}var Xn=null,Jn=[],Bn=function(n){n.crashedEffect=Xn,Jn.push(n)},Qn=function(){Xn=null,Jn.length=0},Vn=function(n){Xn=n},Wn=function(){var n,t,e,r,o=Jn[0],a=Jn.slice(1),c=o.crashedEffect?(n=z(o.crashedEffect))?n.code+" "+zn(n.fileName,n.lineNumber):"":null;return["The above error occurred in task "+Gn(o.meta)+(c?" \n when executing effect "+c:"")].concat(a.map(function(n){return" created by "+Gn(n.meta)}),[(t=Jn,r=(e=[]).concat.apply(e,t.map(function(n){return n.cancelledTasks})),r.length?["Tasks cancelled due to error:"].concat(r).join("\n"):"")]).join("\n")};function Yn(r,n,t,e,o,a,c){var u,f,i,l=An,s=null,v=[],d=Object.create(t),p=function(r,t,o){var a,c=[],u=!1;function f(n){t(),e(),o(n,!0)}function n(e){c.push(e),e.cont=function(n,t){u||(N(c,e),e.cont=q,t?f(n):(e===r&&(a=n),c.length||(u=!0,o(a))))}}function e(){u||(u=!0,c.forEach(function(n){n.cont=q,n.cancel()}),c=[])}return n(r),{addTask:n,cancelAll:e,abort:f,getTasks:function(){return c}}}(n,function(){v.push.apply(v,p.getTasks().map(function(n){return n.meta.name}))},h);function h(t,e){if(e){if(l=mn,Bn({meta:o,cancelledTasks:v}),y.isRoot){var n=Wn();Qn(),r.onError(t,{sagaStack:n})}i=t,s&&s.reject(t)}else t===E?l=bn:l!==bn&&(l=Cn),f=t,s&&s.resolve(t);y.cont(t,e),y.joiners.forEach(function(n){n.cb(t,e)}),y.joiners=null}var y=((u={})[g]=!0,u.id=e,u.meta=o,u.isRoot=a,u.context=d,u.joiners=[],u.queue=p,u.cancel=function(){l===An&&(l=bn,p.cancelAll(),h(E,!1))},u.cont=c,u.end=h,u.setContext=function(n){L(d,n)},u.toPromise=function(){return s||((e={}).promise=new Promise(function(n,t){e.resolve=n,e.reject=t}),s=e,l===mn?s.reject(i):l!==An&&s.resolve(f)),s.promise;var e},u.isRunning=function(){return l===An},u.isCancelled=function(){return l===bn||l===An&&n.status===bn},u.isAborted=function(){return l===mn},u.result=function(){return f},u.error=function(){return i},u);return y}function Zn(u,r,n,o,a,t,e){var f=u.finalizeRunEffect(function(n,t,e){if(S(n))In(n,e);else if(A(n))Zn(u,n,i.context,t,a,!1,e);else if(n&&n[d]){var r=Kn[n.type];r(u,n.payload,e,l)}else e(n)});s.cancel=q;var c={meta:a,cancel:function(){c.status===An&&(c.status=bn,s(E))},status:An},i=Yn(u,c,n,o,a,t,e),l={task:i,digestEffect:v};return e.cancel=i.cancel,s(),i;function s(n,t){try{var e;t?(e=r.throw(n),Qn()):e=D(n)?(c.status=bn,s.cancel(),p(r.return)?r.return(E):{done:!0,value:E}):_(n)?p(r.return)?r.return():{done:!0}:r.next(n),e.done?(c.status!==bn&&(c.status=Cn),c.cont(e.value)):v(e.value,o,s)}catch(n){if(c.status===bn)throw n;c.status=mn,c.cont(n,!0)}}function v(e,n,r,t){void 0===t&&(t="");var o,a=Fn();function c(n,t){o||(o=!0,r.cancel=q,u.sagaMonitor&&(t?u.sagaMonitor.effectRejected(a,n):u.sagaMonitor.effectResolved(a,n)),t&&Vn(e),r(n,t))}u.sagaMonitor&&u.sagaMonitor.effectTriggered({effectId:a,parentEffectId:n,label:t,effect:e}),c.cancel=q,r.cancel=function(){o||(o=!0,c.cancel(),c.cancel=q,u.sagaMonitor&&u.sagaMonitor.effectCancelled(a))},f(e,a,c)}}function $n(n,t){for(var e=n.channel,r=void 0===e?yn():e,o=n.dispatch,a=n.getState,c=n.context,u=void 0===c?{}:c,f=n.sagaMonitor,i=n.effectMiddlewares,l=n.onError,s=void 0===l?P:l,v=arguments.length,d=Array(2<v?v-2:0),p=2;p<v;p++)d[p-2]=arguments[p];var h,y=t.apply(void 0,d),g=Fn();if(f&&(f.rootSagaStarted=f.rootSagaStarted||q,f.effectTriggered=f.effectTriggered||q,f.effectResolved=f.effectResolved||q,f.effectRejected=f.effectRejected||q,f.effectCancelled=f.effectCancelled||q,f.actionDispatched=f.actionDispatched||q,f.rootSagaStarted({effectId:g,saga:t,args:d})),i){var E=function(){for(var n=arguments.length,t=Array(n),e=0;e<n;e++)t[e]=arguments[e];return 0===t.length?function(n){return n}:1===t.length?t[0]:t.reduce(function(n,t){return function(){return n(t.apply(void 0,arguments))}})}.apply(void 0,i);h=function(r){return function(n,t,e){return E(function(n){return r(n,t,e)})(n)}}}else h=O;var S={channel:r,dispatch:I(o),getState:a,sagaMonitor:f,onError:s,finalizeRunEffect:h};return nn(function(){var n=Zn(S,y,u,g,K(t),!0,q);return f&&f.effectResolved(g,n),n})}function nt(t,e){var r;void 0===e&&(e=!0);var n=new Promise(function(n){r=setTimeout(n,t,e)});return n[o]=function(){clearTimeout(r)},n}var tt=function(n,t){var e;return(e={})[d]=!0,e.combinator=!1,e.type=n,e.payload=t,e},et=function(n){return tt(qn,l({},n.payload,{detached:!0}))};function rt(n,t){if(void 0===n&&(n="*"),b(n))return tt(xn,{pattern:n});if(T(n)&&v(t)&&b(t))return tt(xn,{channel:n,pattern:t});if(m(n))return tt(xn,{channel:n});throw Error("take(patternOrChannel): argument "+n+" is not valid channel or a valid pattern")}function ot(n,t){return s(t)&&(t=n,n=void 0),tt("PUT",{channel:n,action:t})}function at(n){var t=tt(Tn,n);return t.combinator=!0,t}function ct(n,t){var e,r=null;return p(n)?e=n:(e=y(n)?(r=n[0],n[1]):(r=n.context,n.fn),r&&h(e)&&p(r[e])&&(e=r[e])),{context:r,fn:e,args:t}}function ut(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return tt(kn,ct(n,e))}function ft(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return tt(qn,ct(n,e))}function it(n){return void 0===n&&(n=c),tt(Ln,n)}function lt(n,t){return tt(jn,{pattern:n,buffer:t})}var st=ut.bind(null,nt),vt=function(n){return{done:!0,value:n}},dt={};function pt(n){return m(n)?"channel":C(n)?n+"":p(n)?n.name:n+""}function ht(r,n,t){var o,a,c,u=n;function e(n,t){if(u===dt)return vt(n);if(t&&!a)throw u=dt,t;o&&o(n);var e=t?r[a](t):r[u]();return c=e.effect,o=e.stateUpdater,a=e.errorState,(u=e.nextState)===dt?vt(n):c}return M(e,function(n){return e(null,n)},t)}function yt(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a,c={done:!1,value:rt(n)},u=function(n){return a=n};return ht({q1:function(){return{nextState:"q2",effect:c,stateUpdater:u}},q2:function(){return{nextState:"q1",effect:(n=a,{done:!1,value:ft.apply(void 0,[t].concat(r,[n]))})};var n}},"q1","takeEvery("+pt(n)+", "+t.name+")")}function gt(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a,c,u={done:!1,value:rt(n)},f=function(n){return{done:!1,value:ft.apply(void 0,[t].concat(r,[n]))}},i=function(n){return a=n},l=function(n){return c=n};return ht({q1:function(){return{nextState:"q2",effect:u,stateUpdater:l}},q2:function(){return a?{nextState:"q3",effect:(n=a,{done:!1,value:it(n)})}:{nextState:"q1",effect:f(c),stateUpdater:i};var n},q3:function(){return{nextState:"q1",effect:f(c),stateUpdater:i}}},"q1","takeLatest("+pt(n)+", "+t.name+")")}function Et(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];var a,c={done:!1,value:rt(n)},u=function(n){return a=n};return ht({q1:function(){return{nextState:"q2",effect:c,stateUpdater:u}},q2:function(){return{nextState:"q1",effect:(n=a,{done:!1,value:ut.apply(void 0,[t].concat(r,[n]))})};var n}},"q1","takeLeading("+pt(n)+", "+t.name+")")}function St(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];var c,u,f={done:!1,value:lt(t,B(1))},i={done:!1,value:st(n)},l=function(n){return c=n},s=function(n){return u=n};return ht({q1:function(){return{nextState:"q2",effect:f,stateUpdater:s}},q2:function(){return{nextState:"q3",effect:{done:!1,value:rt(u)},stateUpdater:l}},q3:function(){return{nextState:"q4",effect:(n=c,{done:!1,value:ft.apply(void 0,[e].concat(o,[n]))})};var n},q4:function(){return{nextState:"q2",effect:i}}},"q1","throttle("+pt(t)+", "+e.name+")")}function At(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];var c,u,f={done:!1,value:rt(t)},i={done:!1,value:at({action:rt(t),debounce:st(n)})},l=function(n){return c=n},s=function(n){return u=n};return ht({q1:function(){return{nextState:"q2",effect:f,stateUpdater:l}},q2:function(){return{nextState:"q3",effect:i,stateUpdater:s}},q3:function(){return u.debounce?{nextState:"q1",effect:(t=c,{done:!1,value:ft.apply(void 0,[e].concat(o,[t]))})}:{nextState:"q2",effect:(n=u.action,{done:!1,value:n}),stateUpdater:l};var n,t}},"q1","debounce("+pt(t)+", "+e.name+")")}var bt=Object.freeze({effectTypes:Un,take:rt,takeMaybe:function(){var n=rt.apply(void 0,arguments);return n.payload.maybe=!0,n},put:ot,putResolve:function(){var n=ot.apply(void 0,arguments);return n.payload.resolve=!0,n},all:function(n){var t=tt("ALL",n);return t.combinator=!0,t},race:at,call:ut,apply:function(n,t,e){return void 0===e&&(e=[]),tt(kn,ct([n,t],e))},cps:function(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return tt("CPS",ct(n,e))},fork:ft,spawn:function(n){for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return et(ft.apply(void 0,[n].concat(e)))},join:function(n){return tt(On,n)},cancel:it,select:function(n){void 0===n&&(n=O);for(var t=arguments.length,e=Array(1<t?t-1:0),r=1;r<t;r++)e[r-1]=arguments[r];return tt(Nn,{selector:n,args:e})},actionChannel:lt,cancelled:function(){return tt(wn,{})},flush:function(n){return tt(Rn,n)},getContext:function(n){return tt(Mn,n)},setContext:function(n){return tt(Pn,n)},delay:st,debounce:function(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];return ft.apply(void 0,[At,n,t,e].concat(o))},retry:function(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];return ut.apply(void 0,[function(n,t,e){for(var r=n,o=arguments.length,a=Array(3<o?o-3:0),c=3;c<o;c++)a[c-3]=arguments[c];var u={done:!1,value:ut.apply(void 0,[e].concat(a))},f={done:!1,value:st(t)};return ht({q1:function(){return{nextState:"q2",effect:u,errorState:"q10"}},q2:function(){return{nextState:dt}},q10:function(n){if((r-=1)<=0)throw n;return{nextState:"q1",effect:f}}},"q1","retry("+e.name+")")},n,t,e].concat(o))},takeEvery:function(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];return ft.apply(void 0,[yt,n,t].concat(r))},takeLatest:function(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];return ft.apply(void 0,[gt,n,t].concat(r))},takeLeading:function(n,t){for(var e=arguments.length,r=Array(2<e?e-2:0),o=2;o<e;o++)r[o-2]=arguments[o];return ft.apply(void 0,[Et,n,t].concat(r))},throttle:function(n,t,e){for(var r=arguments.length,o=Array(3<r?r-3:0),a=3;a<r;a++)o[a-3]=arguments[a];return ft.apply(void 0,[St,n,t,e].concat(o))}});n.effects=bt,n.default=function(n){void 0===n&&(n={});var t,e=n,r=e.context,o=void 0===r?{}:r,a=e.channel,c=void 0===a?yn():a,u=e.sagaMonitor,f=function(n,t){if(null==n)return{};var e,r,o={},a=Object.keys(n);for(r=0;r<a.length;r++)t.indexOf(e=a[r])<0&&(o[e]=n[e]);return o}(e,["context","channel","sagaMonitor"]);function i(n){return t=$n.bind(null,l({},f,{context:o,channel:c,dispatch:n.dispatch,getState:n.getState,sagaMonitor:u})),function(e){return function(n){u&&u.actionDispatched&&u.actionDispatched(n);var t=e(n);return c.put(n),t}}}return i.run=function(){return t.apply(void 0,arguments)},i.setContext=function(n){L(o,n)},i},n.buffers=V,n.CANCEL=o,n.SAGA_LOCATION=u,n.runSaga=$n,n.END=vn,n.isEnd=dn,n.eventChannel=function(n,t){void 0===t&&(t=J());var e,r=!1,o=pn(t),a=function(){r||(r=!0,p(e)&&e(),o.close())};return e=j(e=n(function(n){dn(n)?a():o.put(n)})),r&&e(),{take:o.take,flush:o.flush,close:a}},n.channel=pn,n.multicastChannel=hn,n.stdChannel=yn,n.detach=et,Object.defineProperty(n,"__esModule",{value:!0})}); |
1850
effects.d.ts
@@ -1,754 +0,1286 @@ | ||
import {Action, AnyAction} from "redux"; | ||
import { Action, AnyAction } from 'redux' | ||
import {Last, Reverse} from 'typescript-tuple' | ||
import { | ||
END, TakeableChannel, PuttableChannel, FlushableChannel, | ||
Task, Buffer, Predicate, | ||
} from "./index"; | ||
import {GuardPredicate} from "./utils"; | ||
ActionPattern, | ||
Effect, | ||
Buffer, | ||
CombinatorEffect, | ||
CombinatorEffectDescriptor, | ||
SimpleEffect, | ||
END, | ||
Pattern, | ||
Predicate, | ||
Task, | ||
StrictEffect, | ||
} from '@redux-saga/types' | ||
export type ActionType = string | number | symbol; | ||
import { FlushableChannel, PuttableChannel, TakeableChannel } from './index' | ||
export type StringableActionCreator<A extends Action = Action> = { | ||
(...args: any[]): A; | ||
toString(): string; | ||
}; | ||
export { ActionPattern, Effect, Pattern, SimpleEffect, StrictEffect } | ||
export type SubPattern<T> = | ||
| Predicate<T> | ||
| StringableActionCreator | ||
| ActionType; | ||
export const effectTypes: { | ||
TAKE: 'TAKE' | ||
PUT: 'PUT' | ||
ALL: 'ALL' | ||
RACE: 'RACE' | ||
CALL: 'CALL' | ||
CPS: 'CPS' | ||
FORK: 'FORK' | ||
JOIN: 'JOIN' | ||
CANCEL: 'CANCEL' | ||
SELECT: 'SELECT' | ||
ACTION_CHANNEL: 'ACTION_CHANNEL' | ||
CANCELLED: 'CANCELLED' | ||
FLUSH: 'FLUSH' | ||
GET_CONTEXT: 'GET_CONTEXT' | ||
SET_CONTEXT: 'SET_CONTEXT' | ||
} | ||
export type Pattern<T> = | ||
| SubPattern<T> | ||
| SubPattern<T>[]; | ||
/** | ||
* Creates an Effect description that instructs the middleware to wait for a | ||
* specified action on the Store. The Generator is suspended until an action | ||
* that matches `pattern` is dispatched. | ||
* | ||
* The result of `yield take(pattern)` is an action object being dispatched. | ||
* | ||
* `pattern` is interpreted using the following rules: | ||
* | ||
* - If `take` is called with no arguments or `'*'` all dispatched actions are | ||
* matched (e.g. `take()` will match all actions) | ||
* | ||
* - If it is a function, the action is matched if `pattern(action)` is true | ||
* (e.g. `take(action => action.entities)` will match all actions having a | ||
* (truthy) `entities` field.) | ||
* > Note: if the pattern function has `toString` defined on it, `action.type` | ||
* > will be tested against `pattern.toString()` instead. This is useful if | ||
* > you're using an action creator library like redux-act or redux-actions. | ||
* | ||
* - If it is a String, the action is matched if `action.type === pattern` (e.g. | ||
* `take(INCREMENT_ASYNC)` | ||
* | ||
* - If it is an array, each item in the array is matched with aforementioned | ||
* rules, so the mixed array of strings and function predicates is supported. | ||
* The most common use case is an array of strings though, so that | ||
* `action.type` is matched against all items in the array (e.g. | ||
* `take([INCREMENT, DECREMENT])` and that would match either actions of type | ||
* `INCREMENT` or `DECREMENT`). | ||
* | ||
* The middleware provides a special action `END`. If you dispatch the END | ||
* action, then all Sagas blocked on a take Effect will be terminated regardless | ||
* of the specified pattern. If the terminated Saga has still some forked tasks | ||
* which are still running, it will wait for all the child tasks to terminate | ||
* before terminating the Task. | ||
*/ | ||
export function take<A extends Action>(pattern?: ActionPattern<A>): TakeEffect | ||
export type ActionSubPattern<Guard extends Action = Action> = | ||
| GuardPredicate<Guard, Action> | ||
| StringableActionCreator<Guard> | ||
| Predicate<Action> | ||
| ActionType | ||
/** | ||
* Same as `take(pattern)` but does not automatically terminate the Saga on an | ||
* `END` action. Instead all Sagas blocked on a take Effect will get the `END` | ||
* object. | ||
* | ||
* #### Notes | ||
* | ||
* `takeMaybe` got its name from the FP analogy - it's like instead of having a | ||
* return type of `ACTION` (with automatic handling) we can have a type of | ||
* `Maybe(ACTION)` so we can handle both cases: | ||
* | ||
* - case when there is a `Just(ACTION)` (we have an action) | ||
* - the case of `NOTHING` (channel was closed*). i.e. we need some way to map | ||
* over `END` | ||
* | ||
* internally all `dispatch`ed actions are going through the `stdChannel` which | ||
* is getting closed when `dispatch(END)` happens | ||
*/ | ||
export function takeMaybe<A extends Action>(pattern?: ActionPattern<A>): TakeEffect | ||
export type ActionPattern<Guard extends Action = Action> = | ||
| ActionSubPattern<Guard> | ||
| ActionSubPattern<Guard>[]; | ||
export type TakeEffect = SimpleEffect<'TAKE', TakeEffectDescriptor> | ||
export interface TakeEffectDescriptor { | ||
pattern: ActionPattern; | ||
maybe?: boolean; | ||
pattern: ActionPattern | ||
maybe?: boolean | ||
} | ||
export interface ChannelTakeEffectDescriptor<T> { | ||
channel: TakeableChannel<T>; | ||
pattern?: Pattern<T>; | ||
maybe?: boolean; | ||
} | ||
/** | ||
* Creates an Effect description that instructs the middleware to wait for a | ||
* specified message from the provided Channel. If the channel is already | ||
* closed, then the Generator will immediately terminate following the same | ||
* process described above for `take(pattern)`. | ||
*/ | ||
export function take<T>(channel: TakeableChannel<T>, multicastPattern?: Pattern<T>): ChannelTakeEffect<T> | ||
export interface TakeEffect { | ||
type: 'TAKE'; | ||
payload: TakeEffectDescriptor; | ||
} | ||
/** | ||
* Same as `take(channel)` but does not automatically terminate the Saga on an | ||
* `END` action. Instead all Sagas blocked on a take Effect will get the `END` | ||
* object. | ||
*/ | ||
export function takeMaybe<T>(channel: TakeableChannel<T>, multicastPattern?: Pattern<T>): ChannelTakeEffect<T> | ||
export interface ChannelTakeEffect<T> { | ||
type: 'TAKE'; | ||
payload: ChannelTakeEffectDescriptor<T>; | ||
} | ||
export type ChannelTakeEffect<T> = SimpleEffect<'TAKE', ChannelTakeEffectDescriptor<T>> | ||
export interface Take { | ||
<A extends Action>(pattern?: ActionPattern<A>): TakeEffect; | ||
<T>(channel: TakeableChannel<T>, multicastPattern?: Pattern<T>): ChannelTakeEffect<T>; | ||
export interface ChannelTakeEffectDescriptor<T> { | ||
channel: TakeableChannel<T> | ||
pattern?: Pattern<T> | ||
maybe?: boolean | ||
} | ||
export const take: Take; | ||
export const takeMaybe: Take; | ||
/** | ||
* Spawns a `saga` on each action dispatched to the Store that matches | ||
* `pattern`. | ||
* | ||
* #### Example | ||
* | ||
* In the following example, we create a basic task `fetchUser`. We use | ||
* `takeEvery` to start a new `fetchUser` task on each dispatched | ||
* `USER_REQUESTED` action: | ||
* | ||
* import { takeEvery } from `redux-saga/effects` | ||
* | ||
* function* fetchUser(action) { | ||
* ... | ||
* } | ||
* | ||
* function* watchFetchUser() { | ||
* yield takeEvery('USER_REQUESTED', fetchUser) | ||
* } | ||
* | ||
* #### Notes | ||
* | ||
* `takeEvery` is a high-level API built using `take` and `fork`. Here is how | ||
* the helper could be implemented using the low-level Effects | ||
* | ||
* const takeEvery = (patternOrChannel, saga, ...args) => fork(function*() { | ||
* while (true) { | ||
* const action = yield take(patternOrChannel) | ||
* yield fork(saga, ...args.concat(action)) | ||
* } | ||
* }) | ||
* | ||
* `takeEvery` allows concurrent actions to be handled. In the example above, | ||
* when a `USER_REQUESTED` action is dispatched, a new `fetchUser` task is | ||
* started even if a previous `fetchUser` is still pending (for example, the | ||
* user clicks on a `Load User` button 2 consecutive times at a rapid rate, the | ||
* 2nd click will dispatch a `USER_REQUESTED` action while the `fetchUser` fired | ||
* on the first one hasn't yet terminated) | ||
* | ||
* `takeEvery` doesn't handle out of order responses from tasks. There is no | ||
* guarantee that the tasks will terminate in the same order they were started. | ||
* To handle out of order responses, you may consider `takeLatest` below. | ||
* | ||
* @param pattern for more information see docs for `take(pattern)` | ||
* @param saga a Generator function | ||
* @param args arguments to be passed to the started task. `takeEvery` will add | ||
* the incoming action to the argument list (i.e. the action will be the last | ||
* argument provided to `saga`) | ||
*/ | ||
export function takeEvery<A extends Action>(pattern: ActionPattern<A>, worker: (action: A) => any): ForkEffect | ||
export function takeEvery<A extends Action, Fn extends (...args: any[]) => any>( | ||
pattern: ActionPattern<A>, | ||
worker: Fn, | ||
...args: AllButLast<Parameters<Fn>> | ||
): ForkEffect | ||
/** | ||
* You can also pass in a channel as argument and the behaviour is the same as | ||
* `takeEvery(pattern, saga, ...args)`. | ||
*/ | ||
export function takeEvery<T>(channel: TakeableChannel<T>, worker: (item: T) => any): ForkEffect | ||
export function takeEvery<T, Fn extends (...args: any[]) => any>( | ||
channel: TakeableChannel<T>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<T, Fn> | ||
): ForkEffect | ||
export interface PutEffectDescriptor<A extends Action> { | ||
action: A; | ||
channel: null; | ||
resolve?: boolean; | ||
} | ||
/** | ||
* Spawns a `saga` on each action dispatched to the Store that matches | ||
* `pattern`. And automatically cancels any previous `saga` task started | ||
* previously if it's still running. | ||
* | ||
* Each time an action is dispatched to the store. And if this action matches | ||
* `pattern`, `takeLatest` starts a new `saga` task in the background. If a | ||
* `saga` task was started previously (on the last action dispatched before the | ||
* actual action), and if this task is still running, the task will be | ||
* cancelled. | ||
* | ||
* #### Example | ||
* | ||
* In the following example, we create a basic task `fetchUser`. We use | ||
* `takeLatest` to start a new `fetchUser` task on each dispatched | ||
* `USER_REQUESTED` action. Since `takeLatest` cancels any pending task started | ||
* previously, we ensure that if a user triggers multiple consecutive | ||
* `USER_REQUESTED` actions rapidly, we'll only conclude with the latest action | ||
* | ||
* import { takeLatest } from `redux-saga/effects` | ||
* | ||
* function* fetchUser(action) { | ||
* ... | ||
* } | ||
* | ||
* function* watchLastFetchUser() { | ||
* yield takeLatest('USER_REQUESTED', fetchUser) | ||
* } | ||
* | ||
* #### Notes | ||
* | ||
* `takeLatest` is a high-level API built using `take` and `fork`. Here is how | ||
* the helper could be implemented using the low-level Effects | ||
* | ||
* const takeLatest = (patternOrChannel, saga, ...args) => fork(function*() { | ||
* let lastTask | ||
* while (true) { | ||
* const action = yield take(patternOrChannel) | ||
* if (lastTask) { | ||
* yield cancel(lastTask) // cancel is no-op if the task has already terminated | ||
* } | ||
* lastTask = yield fork(saga, ...args.concat(action)) | ||
* } | ||
* }) | ||
* | ||
* @param pattern for more information see docs for [`take(pattern)`](#takepattern) | ||
* @param saga a Generator function | ||
* @param args arguments to be passed to the started task. `takeLatest` will add | ||
* the incoming action to the argument list (i.e. the action will be the last | ||
* argument provided to `saga`) | ||
*/ | ||
export function takeLatest<A extends Action>(pattern: ActionPattern<A>, worker: (action: A) => any): ForkEffect | ||
export function takeLatest<A extends Action, Fn extends (...args: any[]) => any>( | ||
pattern: ActionPattern<A>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<A, Fn> | ||
): ForkEffect | ||
export interface ChannelPutEffectDescriptor<T> { | ||
action: T; | ||
channel: PuttableChannel<T>; | ||
resolve?: boolean; | ||
} | ||
/** | ||
* You can also pass in a channel as argument and the behaviour is the same as | ||
* `takeLatest(pattern, saga, ...args)`. | ||
*/ | ||
export function takeLatest<T>(channel: TakeableChannel<T>, worker: (item: T) => any): ForkEffect | ||
export function takeLatest<T, Fn extends (...args: any[]) => any>( | ||
channel: TakeableChannel<T>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<T, Fn> | ||
): ForkEffect | ||
export interface PutEffect<A extends Action = AnyAction> { | ||
type: 'PUT'; | ||
payload: PutEffectDescriptor<A>; | ||
} | ||
/** | ||
* Spawns a `saga` on each action dispatched to the Store that matches | ||
* `pattern`. After spawning a task once, it blocks until spawned saga completes | ||
* and then starts to listen for a `pattern` again. | ||
* | ||
* In short, `takeLeading` is listening for the actions when it doesn't run a | ||
* saga. | ||
* | ||
* #### Example | ||
* | ||
* In the following example, we create a basic task `fetchUser`. We use | ||
* `takeLeading` to start a new `fetchUser` task on each dispatched | ||
* `USER_REQUESTED` action. Since `takeLeading` ignores any new coming task | ||
* after it's started, we ensure that if a user triggers multiple consecutive | ||
* `USER_REQUESTED` actions rapidly, we'll only keep on running with the leading | ||
* action | ||
* | ||
* import { takeLeading } from `redux-saga/effects` | ||
* | ||
* function* fetchUser(action) { | ||
* ... | ||
* } | ||
* | ||
* function* watchLastFetchUser() { | ||
* yield takeLeading('USER_REQUESTED', fetchUser) | ||
* } | ||
* | ||
* #### Notes | ||
* | ||
* `takeLeading` is a high-level API built using `take` and `call`. Here is how | ||
* the helper could be implemented using the low-level Effects | ||
* | ||
* const takeLeading = (patternOrChannel, saga, ...args) => fork(function*() { | ||
* while (true) { | ||
* const action = yield take(patternOrChannel); | ||
* yield call(saga, ...args.concat(action)); | ||
* } | ||
* }) | ||
* | ||
* @param pattern for more information see docs for [`take(pattern)`](#takepattern) | ||
* @param saga a Generator function | ||
* @param args arguments to be passed to the started task. `takeLeading` will | ||
* add the incoming action to the argument list (i.e. the action will be the | ||
* last argument provided to `saga`) | ||
*/ | ||
export function takeLeading<A extends Action>(pattern: ActionPattern<A>, worker: (action: A) => any): ForkEffect | ||
export function takeLeading<A extends Action, Fn extends (...args: any[]) => any>( | ||
pattern: ActionPattern<A>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<A, Fn> | ||
): ForkEffect | ||
export interface ChannelPutEffect<T> { | ||
type: 'PUT'; | ||
payload: ChannelPutEffectDescriptor<T>; | ||
} | ||
/** | ||
* You can also pass in a channel as argument and the behaviour is the same as | ||
* `takeLeading(pattern, saga, ...args)`. | ||
*/ | ||
export function takeLeading<T>(channel: TakeableChannel<T>, worker: (item: T) => any): ForkEffect | ||
export function takeLeading<T, Fn extends (...args: any[]) => any>( | ||
channel: TakeableChannel<T>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<T, Fn> | ||
): ForkEffect | ||
export interface Put { | ||
<A extends Action>(action: A): PutEffect<A>; | ||
<T>(channel: PuttableChannel<T>, action: T | END): ChannelPutEffect<T>; | ||
} | ||
export type HelperWorkerParameters<T, Fn extends (...args: any[]) => any> = Last<Parameters<Fn>> extends T | ||
? AllButLast<Parameters<Fn>> | ||
: never | ||
export const put: Put; | ||
export const putResolve: Put; | ||
/** | ||
* Creates an Effect description that instructs the middleware to dispatch an | ||
* action to the Store. This effect is non-blocking and any errors that are | ||
* thrown downstream (e.g. in a reducer) will not bubble back into the saga. | ||
* | ||
* @param action [see Redux `dispatch` documentation for complete info](http://redux.js.org/docs/api/Store.html#dispatch) | ||
*/ | ||
export function put<A extends Action>(action: A): PutEffect<A> | ||
export type GenericAllEffectDescriptor<T> = T[] | {[key: string]: T}; | ||
/** | ||
* Just like `put` but the effect is blocking (if promise is returned from | ||
* `dispatch` it will wait for its resolution) and will bubble up errors from | ||
* downstream. | ||
* | ||
* @param action [see Redux `dispatch` documentation for complete info](http://redux.js.org/docs/api/Store.html#dispatch) | ||
*/ | ||
export function putResolve<A extends Action>(action: A): PutEffect<A> | ||
export interface GenericAllEffect<T> { | ||
type: 'ALL'; | ||
payload: GenericAllEffectDescriptor<T>; | ||
} | ||
export type PutEffect<A extends Action = AnyAction> = SimpleEffect<'PUT', PutEffectDescriptor<A>> | ||
export type AllEffectDescriptor = GenericAllEffectDescriptor<Effect>; | ||
export interface AllEffect { | ||
type: 'ALL' | ||
payload: AllEffectDescriptor; | ||
export interface PutEffectDescriptor<A extends Action> { | ||
action: A | ||
channel: null | ||
resolve?: boolean | ||
} | ||
export function all(effects: Effect[]): AllEffect; | ||
export function all(effects: {[key: string]: Effect}): AllEffect; | ||
/** | ||
* Creates an Effect description that instructs the middleware to put an action | ||
* into the provided channel. | ||
* | ||
* This effect is blocking if the put is *not* buffered but immediately consumed | ||
* by takers. If an error is thrown in any of these takers it will bubble back | ||
* into the saga. | ||
* | ||
* @param channel a `Channel` Object. | ||
* @param action [see Redux `dispatch` documentation for complete info](http://redux.js.org/docs/api/Store.html#dispatch) | ||
*/ | ||
export function put<T>(channel: PuttableChannel<T>, action: T | END): ChannelPutEffect<T> | ||
export function all<T>(effects: T[]): GenericAllEffect<T>; | ||
export function all<T>(effects: {[key: string]: T}): GenericAllEffect<T>; | ||
export type ChannelPutEffect<T> = SimpleEffect<'PUT', ChannelPutEffectDescriptor<T>> | ||
export type GenericRaceEffectDescriptor<T> = {[key: string]: T}; | ||
export interface GenericRaceEffect<T> { | ||
type: 'RACE'; | ||
payload: GenericRaceEffectDescriptor<T>; | ||
export interface ChannelPutEffectDescriptor<T> { | ||
action: T | ||
channel: PuttableChannel<T> | ||
} | ||
export type RaceEffectDescriptor = GenericRaceEffectDescriptor<Effect>; | ||
/** | ||
* Creates an Effect description that instructs the middleware to call the | ||
* function `fn` with `args` as arguments. | ||
* | ||
* #### Notes | ||
* | ||
* `fn` can be either a *normal* or a Generator function. | ||
* | ||
* The middleware invokes the function and examines its result. | ||
* | ||
* If the result is an Iterator object, the middleware will run that Generator | ||
* function, just like it did with the startup Generators (passed to the | ||
* middleware on startup). The parent Generator will be suspended until the | ||
* child Generator terminates normally, in which case the parent Generator is | ||
* resumed with the value returned by the child Generator. Or until the child | ||
* aborts with some error, in which case an error will be thrown inside the | ||
* parent Generator. | ||
* | ||
* If `fn` is a normal function and returns a Promise, the middleware will | ||
* suspend the Generator until the Promise is settled. After the promise is | ||
* resolved the Generator is resumed with the resolved value, or if the Promise | ||
* is rejected an error is thrown inside the Generator. | ||
* | ||
* If the result is not an Iterator object nor a Promise, the middleware will | ||
* immediately return that value back to the saga, so that it can resume its | ||
* execution synchronously. | ||
* | ||
* When an error is thrown inside the Generator, if it has a `try/catch` block | ||
* surrounding the current `yield` instruction, the control will be passed to | ||
* the `catch` block. Otherwise, the Generator aborts with the raised error, and | ||
* if this Generator was called by another Generator, the error will propagate | ||
* to the calling Generator. | ||
* | ||
* @param fn A Generator function, or normal function which either returns a | ||
* Promise as result, or any other value. | ||
* @param args An array of values to be passed as arguments to `fn` | ||
*/ | ||
export function call<Fn extends (...args: any[]) => any>(fn: Fn, ...args: Parameters<Fn>): CallEffect | ||
/** | ||
* Same as `call([context, fn], ...args)` but supports passing a `fn` as string. | ||
* Useful for invoking object's methods, i.e. | ||
* `yield call([localStorage, 'getItem'], 'redux-saga')` | ||
*/ | ||
export function call<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctxAndFnName: [Ctx, Name], | ||
...args: Parameters<Ctx[Name]> | ||
): CallEffect | ||
/** | ||
* Same as `call([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield call({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function call<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctxAndFnName: { context: Ctx; fn: Name }, | ||
...args: Parameters<Ctx[Name]> | ||
): CallEffect | ||
/** | ||
* Same as `call(fn, ...args)` but supports passing a `this` context to `fn`. | ||
* This is useful to invoke object methods. | ||
*/ | ||
export function call<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctxAndFn: [Ctx, Fn], | ||
...args: Parameters<Fn> | ||
): CallEffect | ||
/** | ||
* Same as `call([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield call({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function call<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctxAndFn: { context: Ctx; fn: Fn }, | ||
...args: Parameters<Fn> | ||
): CallEffect | ||
export interface RaceEffect { | ||
type: 'RACE'; | ||
payload: RaceEffectDescriptor; | ||
} | ||
export type CallEffect = SimpleEffect<'CALL', CallEffectDescriptor> | ||
export function race(effects: Effect[]): RaceEffect; | ||
export function race(effects: {[key: string]: Effect}): RaceEffect; | ||
export function race<T>(effects: T[]): GenericRaceEffect<T>; | ||
export function race<T>(effects: {[key: string]: T}): GenericRaceEffect<T>; | ||
export interface CallEffectDescriptor { | ||
context: any; | ||
fn: Function; | ||
args: any[]; | ||
context: any | ||
fn: Function | ||
args: any[] | ||
} | ||
export interface CallEffect { | ||
type: 'CALL'; | ||
payload: CallEffectDescriptor; | ||
} | ||
/** | ||
* Alias for `call([context, fn], ...args)`. | ||
*/ | ||
export function apply<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctx: Ctx, | ||
fnName: Name, | ||
args: Parameters<Ctx[Name]>, | ||
): CallEffect | ||
export function apply<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctx: Ctx, | ||
fn: Fn, | ||
args: Parameters<Fn>, | ||
): CallEffect | ||
type Func0<R> = () => R; | ||
type Func1<R, T1> = (arg1: T1) => R; | ||
type Func2<R, T1, T2> = (arg1: T1, arg2: T2) => R; | ||
type Func3<R, T1, T2, T3> = (arg1: T1, arg2: T2, arg3: T3) => R; | ||
type Func4<R, T1, T2, T3, T4> = (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => R; | ||
type Func5<R, T1, T2, T3, T4, T5> = (arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5) => R; | ||
type Func6Rest<R, T1, T2, T3, T4, T5, T6> = (arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]) => R; | ||
/** | ||
* Creates an Effect description that instructs the middleware to invoke `fn` as | ||
* a Node style function. | ||
* | ||
* @param fn a Node style function. i.e. a function which accepts in addition to | ||
* its arguments, an additional callback to be invoked by `fn` when it | ||
* terminates. The callback accepts two parameters, where the first parameter | ||
* is used to report errors while the second is used to report successful | ||
* results | ||
* @param args an array to be passed as arguments for `fn` | ||
*/ | ||
export function cps<Fn extends (cb: CpsCallback<any>) => any>(fn: Fn): CpsEffect | ||
export function cps<Fn extends (...args: any[]) => any>(fn: Fn, ...args: CpsFunctionParameters<Fn>): CpsEffect | ||
/** | ||
* Same as `cps([context, fn], ...args)` but supports passing a `fn` as string. | ||
* Useful for invoking object's methods, i.e. | ||
* `yield cps([localStorage, 'getItem'], 'redux-saga')` | ||
*/ | ||
export function cps<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => void }, Name extends string>( | ||
ctxAndFnName: [Ctx, Name], | ||
...args: CpsFunctionParameters<Ctx[Name]> | ||
): CpsEffect | ||
/** | ||
* Same as `cps([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield cps({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function cps<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => void }, Name extends string>( | ||
ctxAndFnName: { context: Ctx; fn: Name }, | ||
...args: CpsFunctionParameters<Ctx[Name]> | ||
): CpsEffect | ||
/** | ||
* Same as `cps(fn, ...args)` but supports passing a `this` context to `fn`. | ||
* This is useful to invoke object methods. | ||
*/ | ||
export function cps<Ctx, Fn extends (this: Ctx, ...args: any[]) => void>( | ||
ctxAndFn: [Ctx, Fn], | ||
...args: CpsFunctionParameters<Fn> | ||
): CpsEffect | ||
/** | ||
* Same as `cps([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield cps({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function cps<Ctx, Fn extends (this: Ctx, ...args: any[]) => void>( | ||
ctxAndFn: { context: Ctx; fn: Fn }, | ||
...args: CpsFunctionParameters<Fn> | ||
): CpsEffect | ||
export type CallEffectFn<F extends Function> = | ||
F | [any, F] | {context: any, fn: F}; | ||
export type CpsFunctionParameters<Fn extends (...args: any[]) => any> = Last< | ||
Parameters<Fn> | ||
> extends CpsCallback<any> | ||
? AllButLast<Parameters<Fn>> | ||
: never | ||
export type CallEffectNamedFn<C extends {[P in Name]: Function}, | ||
Name extends string> = | ||
[C, Name] | {context: C, fn: Name}; | ||
interface CallEffectFactory<Effect> { | ||
<C extends {[P in N]: Func0<R>}, N extends string, R>( | ||
fn: CallEffectNamedFn<C, N>): Effect; | ||
<C extends {[P in N]: Func1<R, T1>}, N extends string, R, T1>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1): Effect; | ||
<C extends {[P in N]: Func2<R, T1, T2>}, N extends string, R, T1, T2>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2): Effect; | ||
<C extends {[P in N]: Func3<R, T1, T2, T3>}, N extends string, | ||
R, T1, T2, T3>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3): Effect; | ||
<C extends {[P in N]: Func4<R, T1, T2, T3, T4>}, N extends string, | ||
R, T1, T2, T3, T4>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): Effect; | ||
<C extends {[P in N]: Func5<R, T1, T2, T3, T4, T5>}, N extends string, | ||
R, T1, T2, T3, T4, T5>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): Effect; | ||
<C extends {[P in N]: Func6Rest<R, T1, T2, T3, T4, T5, T6>}, N extends string, | ||
R, T1, T2, T3, T4, T5, T6>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): Effect; | ||
<R>(fn: CallEffectFn<Func0<R>>): Effect; | ||
<R, T1>(fn: CallEffectFn<Func1<R, T1>>, | ||
arg1: T1): Effect; | ||
<R, T1, T2>(fn: CallEffectFn<Func2<R, T1, T2>>, | ||
arg1: T1, arg2: T2): Effect; | ||
<R, T1, T2, T3>(fn: CallEffectFn<Func3<R, T1, T2, T3>>, | ||
arg1: T1, arg2: T2, arg3: T3): Effect; | ||
<R, T1, T2, T3, T4>(fn: CallEffectFn<Func4<R, T1, T2, T3, T4>>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): Effect; | ||
<R, T1, T2, T3, T4, T5>(fn: CallEffectFn<Func5<R, T1, T2, T3, T4, T5>>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): Effect; | ||
<R, T1, T2, T3, T4, T5, T6>(fn: CallEffectFn<Func6Rest<R, T1, T2, T3, T4, T5, T6>>, | ||
arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5, arg6: T6, ...rest: any[]): Effect; | ||
export interface CpsCallback<R> { | ||
(error: any, result: R): void | ||
cancel?(): void | ||
} | ||
export const call: CallEffectFactory<CallEffect>; | ||
export type CpsEffect = SimpleEffect<'CPS', CallEffectDescriptor> | ||
/** | ||
* Creates an Effect description that instructs the middleware to perform a | ||
* *non-blocking call* on `fn` | ||
* | ||
* returns a `Task` object. | ||
* | ||
* #### Note | ||
* | ||
* `fork`, like `call`, can be used to invoke both normal and Generator | ||
* functions. But, the calls are non-blocking, the middleware doesn't suspend | ||
* the Generator while waiting for the result of `fn`. Instead as soon as `fn` | ||
* is invoked, the Generator resumes immediately. | ||
* | ||
* `fork`, alongside `race`, is a central Effect for managing concurrency | ||
* between Sagas. | ||
* | ||
* The result of `yield fork(fn ...args)` is a `Task` object. An object | ||
* with some useful methods and properties. | ||
* | ||
* All forked tasks are *attached* to their parents. When the parent terminates | ||
* the execution of its own body of instructions, it will wait for all forked | ||
* tasks to terminate before returning. | ||
* | ||
* Errors from child tasks automatically bubble up to their parents. If any | ||
* forked task raises an uncaught error, then the parent task will abort with | ||
* the child Error, and the whole Parent's execution tree (i.e. forked tasks + | ||
* the *main task* represented by the parent's body if it's still running) will | ||
* be cancelled. | ||
* | ||
* Cancellation of a forked Task will automatically cancel all forked tasks that | ||
* are still executing. It'll also cancel the current Effect where the cancelled | ||
* task was blocked (if any). | ||
* | ||
* If a forked task fails *synchronously* (ie: fails immediately after its | ||
* execution before performing any async operation), then no Task is returned, | ||
* instead the parent will be aborted as soon as possible (since both parent and | ||
* child execute in parallel, the parent will abort as soon as it takes notice | ||
* of the child failure). | ||
* | ||
* To create *detached* forks, use `spawn` instead. | ||
* | ||
* @param fn A Generator function, or normal function which returns a Promise as result | ||
* @param args An array of values to be passed as arguments to `fn` | ||
*/ | ||
export function fork<Fn extends (...args: any[]) => any>(fn: Fn, ...args: Parameters<Fn>): ForkEffect | ||
/** | ||
* Same as `fork([context, fn], ...args)` but supports passing a `fn` as string. | ||
* Useful for invoking object's methods, i.e. | ||
* `yield fork([localStorage, 'getItem'], 'redux-saga')` | ||
*/ | ||
export function fork<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctxAndFnName: [Ctx, Name], | ||
...args: Parameters<Ctx[Name]> | ||
): ForkEffect | ||
/** | ||
* Same as `fork([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield fork({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function fork<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctxAndFnName: { context: Ctx; fn: Name }, | ||
...args: Parameters<Ctx[Name]> | ||
): ForkEffect | ||
/** | ||
* Same as `fork(fn, ...args)` but supports passing a `this` context to `fn`. | ||
* This is useful to invoke object methods. | ||
*/ | ||
export function fork<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctxAndFn: [Ctx, Fn], | ||
...args: Parameters<Fn> | ||
): ForkEffect | ||
/** | ||
* Same as `fork([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield fork({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function fork<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctxAndFn: { context: Ctx; fn: Fn }, | ||
...args: Parameters<Fn> | ||
): ForkEffect | ||
export function apply<C extends {[P in N]: Func0<R>}, | ||
N extends string, R>( | ||
context: C, fn: N): CallEffect; | ||
export function apply<C extends {[P in N]: Func1<R, T1>}, | ||
N extends string, | ||
R, T1>( | ||
context: C, fn: N, | ||
args: [T1]): CallEffect; | ||
export function apply<C extends {[P in N]: Func2<R, T1, T2>}, | ||
N extends string, | ||
R, T1, T2>( | ||
context: C, fn: N, | ||
args: [T1, T2]): CallEffect; | ||
export function apply<C extends {[P in N]: Func3<R, T1, T2, T3>}, | ||
N extends string, | ||
R, T1, T2, T3>( | ||
context: C, fn: N, | ||
args: [T1, T2, T3]): CallEffect; | ||
export function apply<C extends {[P in N]: Func4<R, T1, T2, T3, T4>}, | ||
N extends string, | ||
R, T1, T2, T3, T4>( | ||
context: C, fn: N, | ||
args: [T1, T2, T3, T4]): CallEffect; | ||
export function apply<C extends {[P in N]: Func5<R, T1, T2, T3, T4, T5>}, | ||
N extends string, | ||
R, T1, T2, T3, T4, T5>( | ||
context: C, fn: N, | ||
args: [T1, T2, T3, T4, T5]): CallEffect; | ||
export function apply<C extends {[P in N]: Func6Rest<R, T1, T2, T3, T4, T5, T6>}, | ||
N extends string, | ||
R, T1, T2, T3, T4, T5, T6>( | ||
context: C, fn: N, | ||
args: any[] & { | ||
0: T1; 1: T2; 2: T3; 3: T4; 4: T5; 5: T6; | ||
}): CallEffect; | ||
export type ForkEffect = SimpleEffect<'FORK', ForkEffectDescriptor> | ||
export function apply<R>(context: any, fn: Func0<R>): CallEffect; | ||
export function apply<R, T1>(context: any, fn: Func1<R, T1>, | ||
args: [T1]): CallEffect; | ||
export function apply<R, T1, T2>(context: any, fn: Func2<R, T1, T2>, | ||
args: [T1, T2]): CallEffect; | ||
export function apply<R, T1, T2, T3>(context: any, fn: Func3<R, T1, T2, T3>, | ||
args: [T1, T2, T3]): CallEffect; | ||
export function apply<R, T1, T2, T3, T4>(context: any, | ||
fn: Func4<R, T1, T2, T3, T4>, | ||
args: [T1, T2, T3, T4]): CallEffect; | ||
export function apply<R, T1, T2, T3, T4, T5>( | ||
context: any, fn: Func5<R, T1, T2, T3, T4, T5>, args: [T1, T2, T3, T4, T5], | ||
): CallEffect; | ||
export function apply<R, T1, T2, T3, T4, T5, T6>( | ||
context: any, fn: Func6Rest<R, T1, T2, T3, T4, T5, T6>, args: any[] & { | ||
0: T1; 1: T2; 2: T3; 3: T4; 4: T5; 5: T6; | ||
}, | ||
): CallEffect; | ||
export interface CpsEffect { | ||
type: 'CPS'; | ||
payload: CallEffectDescriptor; | ||
} | ||
interface CpsCallback<R> { | ||
(error: any, result: R): void; | ||
cancel?(): void; | ||
} | ||
export function cps<C extends {[P in N]: Func1<void, CpsCallback<R>>}, | ||
N extends string, R>( | ||
fn: CallEffectNamedFn<C, N>): CpsEffect; | ||
export function cps<C extends {[P in N]: Func2<void, T1, CpsCallback<R>>}, | ||
N extends string, | ||
R, T1>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1): CpsEffect; | ||
export function cps<C extends {[P in N]: Func3<void, T1, T2, CpsCallback<R>>}, | ||
N extends string, | ||
R, T1, T2>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2): CpsEffect; | ||
export function cps<C extends {[P in N]: Func4<void, T1, T2, T3, CpsCallback<R>>}, | ||
N extends string, | ||
R, T1, T2, T3>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3): CpsEffect; | ||
export function cps<C extends {[P in N]: Func5<void, T1, T2, T3, T4, CpsCallback<R>>}, | ||
N extends string, | ||
R, T1, T2, T3, T4>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): CpsEffect; | ||
export function cps<C extends {[P in N]: | ||
Func6Rest<void, T1, T2, T3, T4, T5, CpsCallback<R>>}, | ||
N extends string, | ||
R, T1, T2, T3, T4, T5>( | ||
fn: CallEffectNamedFn<C, N>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, ...rest: any[]): CpsEffect; | ||
export function cps<R>(fn: CallEffectFn<Func1<void, CpsCallback<R>>>): CpsEffect; | ||
export function cps<R, T1>(fn: CallEffectFn<Func2<void, T1, CpsCallback<R>>>, | ||
arg1: T1): CpsEffect; | ||
export function cps<R, T1, T2>(fn: CallEffectFn<Func3<void, T1, T2, CpsCallback<R>>>, | ||
arg1: T1, arg2: T2): CpsEffect; | ||
export function cps<R, T1, T2, T3>( | ||
fn: CallEffectFn<Func4<void, T1, T2, T3, CpsCallback<R>>>, | ||
arg1: T1, arg2: T2, arg3: T3): CpsEffect; | ||
export function cps<R, T1, T2, T3, T4>( | ||
fn: CallEffectFn<Func5<void, T1, T2, T3, T4, CpsCallback<R>>>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): CpsEffect; | ||
export function cps<R, T1, T2, T3, T4, T5>( | ||
fn: CallEffectFn<Func6Rest<void, T1, T2, T3, T4, T5, any>>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, | ||
...rest: any[]): CpsEffect; | ||
export interface ForkEffectDescriptor extends CallEffectDescriptor { | ||
detached?: boolean; | ||
detached?: boolean | ||
} | ||
export interface ForkEffect { | ||
type: 'FORK'; | ||
payload: ForkEffectDescriptor; | ||
} | ||
/** | ||
* Same as `fork(fn, ...args)` but creates a *detached* task. A detached task | ||
* remains independent from its parent and acts like a top-level task. The | ||
* parent will not wait for detached tasks to terminate before returning and all | ||
* events which may affect the parent or the detached task are completely | ||
* independents (error, cancellation). | ||
*/ | ||
export function spawn<Fn extends (...args: any[]) => any>(fn: Fn, ...args: Parameters<Fn>): ForkEffect | ||
/** | ||
* Same as `spawn([context, fn], ...args)` but supports passing a `fn` as string. | ||
* Useful for invoking object's methods, i.e. | ||
* `yield spawn([localStorage, 'getItem'], 'redux-saga')` | ||
*/ | ||
export function spawn<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctxAndFnName: [Ctx, Name], | ||
...args: Parameters<Ctx[Name]> | ||
): ForkEffect | ||
/** | ||
* Same as `spawn([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield spawn({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function spawn<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>( | ||
ctxAndFnName: { context: Ctx; fn: Name }, | ||
...args: Parameters<Ctx[Name]> | ||
): ForkEffect | ||
/** | ||
* Same as `spawn(fn, ...args)` but supports passing a `this` context to `fn`. | ||
* This is useful to invoke object methods. | ||
*/ | ||
export function spawn<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctxAndFn: [Ctx, Fn], | ||
...args: Parameters<Fn> | ||
): ForkEffect | ||
/** | ||
* Same as `spawn([context, fn], ...args)` but supports passing `context` and | ||
* `fn` as properties of an object, i.e. | ||
* `yield spawn({context: localStorage, fn: localStorage.getItem}, 'redux-saga')`. | ||
* `fn` can be a string or a function. | ||
*/ | ||
export function spawn<Ctx, Fn extends (this: Ctx, ...args: any[]) => any>( | ||
ctxAndFn: { context: Ctx; fn: Fn }, | ||
...args: Parameters<Fn> | ||
): ForkEffect | ||
export const fork: CallEffectFactory<ForkEffect>; | ||
export const spawn: CallEffectFactory<ForkEffect>; | ||
/** | ||
* Creates an Effect description that instructs the middleware to wait for the | ||
* result of a previously forked task. | ||
* | ||
* #### Notes | ||
* | ||
* `join` will resolve to the same outcome of the joined task (success or | ||
* error). If the joined task is cancelled, the cancellation will also propagate | ||
* to the Saga executing the join effect. Similarly, any potential callers of | ||
* those joiners will be cancelled as well. | ||
* | ||
* @param task A `Task` object returned by a previous `fork` | ||
*/ | ||
export function join(task: Task): JoinEffect | ||
/** | ||
* Creates an Effect description that instructs the middleware to wait for the | ||
* results of previously forked tasks. | ||
* | ||
* @param tasks A `Task` is the object returned by a previous `fork` | ||
*/ | ||
export function join(tasks: Task[]): JoinEffect | ||
export type JoinEffect = SimpleEffect<'JOIN', JoinEffectDescriptor> | ||
export type JoinEffectDescriptor = Task | Task[]; | ||
export type JoinEffectDescriptor = Task | Task[] | ||
export interface JoinEffect { | ||
type: 'JOIN'; | ||
payload: JoinEffectDescriptor; | ||
} | ||
/** | ||
* Creates an Effect description that instructs the middleware to cancel a | ||
* previously forked task. | ||
* | ||
* #### Notes | ||
* | ||
* To cancel a running task, the middleware will invoke `return` on the | ||
* underlying Generator object. This will cancel the current Effect in the task | ||
* and jump to the finally block (if defined). | ||
* | ||
* Inside the finally block, you can execute any cleanup logic or dispatch some | ||
* action to keep the store in a consistent state (e.g. reset the state of a | ||
* spinner to false when an ajax request is cancelled). You can check inside the | ||
* finally block if a Saga was cancelled by issuing a `yield cancelled()`. | ||
* | ||
* Cancellation propagates downward to child sagas. When cancelling a task, the | ||
* middleware will also cancel the current Effect (where the task is currently | ||
* blocked). If the current Effect is a call to another Saga, it will be also | ||
* cancelled. When cancelling a Saga, all *attached forks* (sagas forked using | ||
* `yield fork()`) will be cancelled. This means that cancellation effectively | ||
* affects the whole execution tree that belongs to the cancelled task. | ||
* | ||
* `cancel` is a non-blocking Effect. i.e. the Saga executing it will resume | ||
* immediately after performing the cancellation. | ||
* | ||
* For functions which return Promise results, you can plug your own | ||
* cancellation logic by attaching a `[CANCEL]` to the promise. | ||
* | ||
* The following example shows how to attach cancellation logic to a Promise | ||
* result: | ||
* | ||
* import { CANCEL } from 'redux-saga' | ||
* import { fork, cancel } from 'redux-saga/effects' | ||
* | ||
* function myApi() { | ||
* const promise = myXhr(...) | ||
* | ||
* promise[CANCEL] = () => myXhr.abort() | ||
* return promise | ||
* } | ||
* | ||
* function* mySaga() { | ||
* | ||
* const task = yield fork(myApi) | ||
* | ||
* // ... later | ||
* // will call promise[CANCEL] on the result of myApi | ||
* yield cancel(task) | ||
* } | ||
* | ||
* redux-saga will automatically cancel jqXHR objects using their `abort` method. | ||
* | ||
* @param task A `Task` object returned by a previous `fork` | ||
*/ | ||
export function cancel(task: Task): CancelEffect | ||
/** | ||
* Creates an Effect description that instructs the middleware to cancel | ||
* previously forked tasks. | ||
* | ||
* #### Notes | ||
* | ||
* It wraps the array of tasks in cancel effects, roughly becoming the | ||
* equivalent of `yield tasks.map(t => cancel(t))`. | ||
* | ||
* @param tasks A `Task` is the object returned by a previous `fork` | ||
*/ | ||
export function cancel(tasks: Task[]): CancelEffect | ||
/** | ||
* Creates an Effect description that instructs the middleware to cancel a task | ||
* in which it has been yielded (self-cancellation). It allows to reuse | ||
* destructor-like logic inside a `finally` blocks for both outer | ||
* (`cancel(task)`) and self (`cancel()`) cancellations. | ||
* | ||
* #### Example | ||
* | ||
* function* deleteRecord({ payload }) { | ||
* try { | ||
* const { confirm, deny } = yield call(prompt); | ||
* if (confirm) { | ||
* yield put(actions.deleteRecord.confirmed()) | ||
* } | ||
* if (deny) { | ||
* yield cancel() | ||
* } | ||
* } catch(e) { | ||
* // handle failure | ||
* } finally { | ||
* if (yield cancelled()) { | ||
* // shared cancellation logic | ||
* yield put(actions.deleteRecord.cancel(payload)) | ||
* } | ||
* } | ||
* } | ||
*/ | ||
export function cancel(): CancelEffect | ||
export function join(task: Task): JoinEffect; | ||
export function join(tasks: Task[]): JoinEffect; | ||
export type CancelEffect = SimpleEffect<'CANCEL', CancelEffectDescriptor> | ||
export type CancelEffectDescriptor = Task | Task[] | SELF_CANCELLATION | ||
type SELF_CANCELLATION = '@@redux-saga/SELF_CANCELLATION' | ||
type SELF_CANCELLATION = '@@redux-saga/SELF_CANCELLATION'; | ||
export type CancelEffectDescriptor = Task | Task[] | SELF_CANCELLATION; | ||
/** | ||
* Creates an effect that instructs the middleware to invoke the provided | ||
* selector on the current Store's state (i.e. returns the result of | ||
* `selector(getState(), ...args)`). | ||
* | ||
* If `select` is called without argument (i.e. `yield select()`) then the | ||
* effect is resolved with the entire state (the same result of a `getState()` | ||
* call). | ||
* | ||
* > It's important to note that when an action is dispatched to the store, the | ||
* middleware first forwards the action to the reducers and then notifies the | ||
* Sagas. This means that when you query the Store's State, you get the State | ||
* **after** the action has been applied. However, this behavior is only | ||
* guaranteed if all subsequent middlewares call `next(action)` synchronously. | ||
* If any subsequent middleware calls `next(action)` asynchronously (which is | ||
* unusual but possible), then the sagas will get the state from **before** the | ||
* action is applied. Therefore it is recommended to review the source of each | ||
* subsequent middleware to ensure it calls `next(action)` synchronously, or | ||
* else ensure that redux-saga is the last middleware in the call chain. | ||
* | ||
* #### Notes | ||
* | ||
* Preferably, a Saga should be autonomous and should not depend on the Store's | ||
* state. This makes it easy to modify the state implementation without | ||
* affecting the Saga code. A saga should preferably depend only on its own | ||
* internal control state when possible. But sometimes, one could find it more | ||
* convenient for a Saga to query the state instead of maintaining the needed | ||
* data by itself (for example, when a Saga duplicates the logic of invoking | ||
* some reducer to compute a state that was already computed by the Store). | ||
* | ||
* For example, suppose we have this state shape in our application: | ||
* | ||
* state = { | ||
* cart: {...} | ||
* } | ||
* | ||
* We can create a *selector*, i.e. a function which knows how to extract the | ||
* `cart` data from the State: | ||
* | ||
* `./selectors` | ||
* | ||
* export const getCart = state => state.cart | ||
* | ||
* | ||
* Then we can use that selector from inside a Saga using the `select` Effect: | ||
* | ||
* `./sagas.js` | ||
* | ||
* import { take, fork, select } from 'redux-saga/effects' | ||
* import { getCart } from './selectors' | ||
* | ||
* function* checkout() { | ||
* // query the state using the exported selector | ||
* const cart = yield select(getCart) | ||
* | ||
* // ... call some API endpoint then dispatch a success/error action | ||
* } | ||
* | ||
* export default function* rootSaga() { | ||
* while (true) { | ||
* yield take('CHECKOUT_REQUEST') | ||
* yield fork(checkout) | ||
* } | ||
* } | ||
* | ||
* `checkout` can get the needed information directly by using | ||
* `select(getCart)`. The Saga is coupled only with the `getCart` selector. If | ||
* we have many Sagas (or React Components) that needs to access the `cart` | ||
* slice, they will all be coupled to the same function `getCart`. And if we now | ||
* change the state shape, we need only to update `getCart`. | ||
* | ||
* @param selector a function `(state, ...args) => args`. It takes the current | ||
* state and optionally some arguments and returns a slice of the current | ||
* Store's state | ||
* @param args optional arguments to be passed to the selector in addition of | ||
* `getState`. | ||
*/ | ||
export function select(): SelectEffect | ||
export function select<Fn extends (state: any, ...args: any[]) => any>( | ||
selector: Fn, | ||
...args: Tail<Parameters<Fn>> | ||
): SelectEffect | ||
export interface CancelEffect { | ||
type: 'CANCEL'; | ||
payload: CancelEffectDescriptor; | ||
} | ||
export type SelectEffect = SimpleEffect<'SELECT', SelectEffectDescriptor> | ||
export function cancel(): CancelEffect; | ||
export function cancel(task: Task): CancelEffect; | ||
export function cancel(tasks: Task[]): CancelEffect; | ||
export interface SelectEffectDescriptor { | ||
selector(state: any, ...args: any[]): any; | ||
args: any[]; | ||
selector(state: any, ...args: any[]): any | ||
args: any[] | ||
} | ||
export interface SelectEffect { | ||
type: 'SELECT'; | ||
payload: SelectEffectDescriptor; | ||
} | ||
/** | ||
* Creates an effect that instructs the middleware to queue the actions matching | ||
* `pattern` using an event channel. Optionally, you can provide a buffer to | ||
* control buffering of the queued actions. | ||
* | ||
* #### Example | ||
* | ||
* The following code creates a channel to buffer all `USER_REQUEST` actions. | ||
* Note that even the Saga may be blocked on the `call` effect. All actions that | ||
* come while it's blocked are automatically buffered. This causes the Saga to | ||
* execute the API calls one at a time | ||
* | ||
* import { actionChannel, call } from 'redux-saga/effects' | ||
* import api from '...' | ||
* | ||
* function* takeOneAtMost() { | ||
* const chan = yield actionChannel('USER_REQUEST') | ||
* while (true) { | ||
* const {payload} = yield take(chan) | ||
* yield call(api.getUser, payload) | ||
* } | ||
* } | ||
* | ||
* @param pattern see API for `take(pattern)` | ||
* @param buffer a `Buffer` object | ||
*/ | ||
export function actionChannel(pattern: ActionPattern, buffer?: Buffer<Action>): ActionChannelEffect | ||
export function select(): SelectEffect; | ||
export function select<S, R>(selector: Func1<R, S>): SelectEffect; | ||
export function select<S, R, T1>(selector: Func2<R, S, T1>, | ||
arg1: T1): SelectEffect; | ||
export function select<S, R, T1, T2>(selector: Func3<R, S, T1, T2>, | ||
arg1: T1, arg2: T2): SelectEffect; | ||
export function select<S, R, T1, T2, T3>( | ||
selector: Func4<R, S, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): SelectEffect; | ||
export function select<S, R, T1, T2, T3, T4>( | ||
selector: Func5<R, S, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): SelectEffect; | ||
export function select<S, R, T1, T2, T3, T4, T5>( | ||
selector: Func6Rest<R, S, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, | ||
...rest: any[]): SelectEffect; | ||
export type ActionChannelEffect = SimpleEffect<'ACTION_CHANNEL', ActionChannelEffectDescriptor> | ||
export interface ActionChannelEffectDescriptor { | ||
pattern: ActionPattern; | ||
buffer?: Buffer<Action>; | ||
pattern: ActionPattern | ||
buffer?: Buffer<Action> | ||
} | ||
export interface ActionChannelEffect { | ||
type: 'ACTION_CHANNEL'; | ||
payload: ActionChannelEffectDescriptor; | ||
} | ||
/** | ||
* Creates an effect that instructs the middleware to flush all buffered items | ||
* from the channel. Flushed items are returned back to the saga, so they can be | ||
* utilized if needed. | ||
* | ||
* #### Example | ||
* | ||
* function* saga() { | ||
* const chan = yield actionChannel('ACTION') | ||
* | ||
* try { | ||
* while (true) { | ||
* const action = yield take(chan) | ||
* // ... | ||
* } | ||
* } finally { | ||
* const actions = yield flush(chan) | ||
* // ... | ||
* } | ||
* } | ||
* | ||
* @param channel a `Channel` Object. | ||
*/ | ||
export function flush<T>(channel: FlushableChannel<T>): FlushEffect<T> | ||
export function actionChannel( | ||
pattern: ActionPattern, buffer?: Buffer<Action>, | ||
): ActionChannelEffect; | ||
export type FlushEffect<T> = SimpleEffect<'FLUSH', FlushEffectDescriptor<T>> | ||
export type FlushEffectDescriptor<T> = FlushableChannel<T> | ||
export type CancelledEffectDescriptor = {}; | ||
/** | ||
* Creates an effect that instructs the middleware to return whether this | ||
* generator has been cancelled. Typically you use this Effect in a finally | ||
* block to run Cancellation specific code | ||
* | ||
* #### Example | ||
* | ||
* function* saga() { | ||
* try { | ||
* // ... | ||
* } finally { | ||
* if (yield cancelled()) { | ||
* // logic that should execute only on Cancellation | ||
* } | ||
* // logic that should execute in all situations (e.g. closing a channel) | ||
* } | ||
* } | ||
*/ | ||
export function cancelled(): CancelledEffect | ||
export interface CancelledEffect { | ||
type: 'CANCELLED'; | ||
payload: CancelledEffectDescriptor; | ||
} | ||
export type CancelledEffect = SimpleEffect<'CANCELLED', CancelledEffectDescriptor> | ||
export function cancelled(): CancelledEffect; | ||
export type CancelledEffectDescriptor = {} | ||
/** | ||
* Creates an effect that instructs the middleware to update its own context. | ||
* This effect extends saga's context instead of replacing it. | ||
*/ | ||
export function setContext<C extends object>(props: C): SetContextEffect<C> | ||
export type FlushEffectDescriptor<T> = FlushableChannel<T>; | ||
export type SetContextEffect<C extends object> = SimpleEffect<'SET_CONTEXT', SetContextEffectDescriptor<C>> | ||
export interface FlushEffect<T> { | ||
type: 'FLUSH'; | ||
payload: FlushEffectDescriptor<T>; | ||
} | ||
export type SetContextEffectDescriptor<C extends object> = C | ||
export function flush<T>(channel: FlushableChannel<T>): FlushEffect<T>; | ||
/** | ||
* Creates an effect that instructs the middleware to return a specific property | ||
* of saga's context. | ||
*/ | ||
export function getContext(prop: string): GetContextEffect | ||
export type GetContextEffect = SimpleEffect<'GET_CONTEXT', GetContextEffectDescriptor> | ||
export type GetContextEffectDescriptor = string; | ||
export type GetContextEffectDescriptor = string | ||
export interface GetContextEffect { | ||
type: 'GET_CONTEXT'; | ||
payload: GetContextEffectDescriptor; | ||
} | ||
/** | ||
* Returns an effect descriptor to block execution for `ms` milliseconds and return `val` value. | ||
*/ | ||
export function delay<T = true>(ms: number, val?: T): CallEffect | ||
export function getContext(prop: string): GetContextEffect; | ||
/** | ||
* Spawns a `saga` on an action dispatched to the Store that matches `pattern`. | ||
* After spawning a task it's still accepting incoming actions into the | ||
* underlying `buffer`, keeping at most 1 (the most recent one), but in the same | ||
* time holding up with spawning new task for `ms` milliseconds (hence its name - | ||
* `throttle`). Purpose of this is to ignore incoming actions for a given | ||
* period of time while processing a task. | ||
* | ||
* #### Example | ||
* | ||
* In the following example, we create a basic task `fetchAutocomplete`. We use | ||
* `throttle` to start a new `fetchAutocomplete` task on dispatched | ||
* `FETCH_AUTOCOMPLETE` action. However since `throttle` ignores consecutive | ||
* `FETCH_AUTOCOMPLETE` for some time, we ensure that user won't flood our | ||
* server with requests. | ||
* | ||
* import { call, put, throttle } from `redux-saga/effects` | ||
* | ||
* function* fetchAutocomplete(action) { | ||
* const autocompleteProposals = yield call(Api.fetchAutocomplete, action.text) | ||
* yield put({type: 'FETCHED_AUTOCOMPLETE_PROPOSALS', proposals: autocompleteProposals}) | ||
* } | ||
* | ||
* function* throttleAutocomplete() { | ||
* yield throttle(1000, 'FETCH_AUTOCOMPLETE', fetchAutocomplete) | ||
* } | ||
* | ||
* #### Notes | ||
* | ||
* `throttle` is a high-level API built using `take`, `fork` and | ||
* `actionChannel`. Here is how the helper could be implemented using the | ||
* low-level Effects | ||
* | ||
* const throttle = (ms, pattern, task, ...args) => fork(function*() { | ||
* const throttleChannel = yield actionChannel(pattern, buffers.sliding(1)) | ||
* | ||
* while (true) { | ||
* const action = yield take(throttleChannel) | ||
* yield fork(task, ...args, action) | ||
* yield delay(ms) | ||
* } | ||
* }) | ||
* | ||
* @param ms length of a time window in milliseconds during which actions will | ||
* be ignored after the action starts processing | ||
* @param pattern for more information see docs for `take(pattern)` | ||
* @param saga a Generator function | ||
* @param args arguments to be passed to the started task. `throttle` will add | ||
* the incoming action to the argument list (i.e. the action will be the last | ||
* argument provided to `saga`) | ||
*/ | ||
export function throttle<A extends Action>( | ||
ms: number, | ||
pattern: ActionPattern<A>, | ||
worker: (action: A) => any, | ||
): ForkEffect | ||
export function throttle<A extends Action, Fn extends (...args: any[]) => any>( | ||
ms: number, | ||
pattern: ActionPattern<A>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<A, Fn> | ||
): ForkEffect | ||
export type SetContextEffectDescriptor<C extends object> = C; | ||
export interface SetContextEffect<C extends object> { | ||
type: 'SET_CONTEXT'; | ||
payload: SetContextEffectDescriptor<C>; | ||
} | ||
export function setContext<C extends object>(props: C): SetContextEffect<C>; | ||
export interface RootEffect { | ||
root: true; | ||
saga(...args: any[]): Iterator<any>; | ||
args: any[]; | ||
} | ||
export type Effect = | ||
RootEffect | | ||
TakeEffect | ChannelTakeEffect<any> | | ||
PutEffect<any> | ChannelPutEffect<any> | | ||
AllEffect | RaceEffect | CallEffect | | ||
CpsEffect | ForkEffect | JoinEffect | CancelEffect | SelectEffect | | ||
ActionChannelEffect | CancelledEffect | FlushEffect<any> | | ||
GetContextEffect | SetContextEffect<any>; | ||
type HelperFunc0<A> = (action: A) => any; | ||
type HelperFunc1<A, T1> = (arg1: T1, action: A) => any; | ||
type HelperFunc2<A, T1, T2> = (arg1: T1, arg2: T2, action: A) => any; | ||
type HelperFunc3<A, T1, T2, T3> = (arg1: T1, arg2: T2, arg3: T3, | ||
action: A) => any; | ||
type HelperFunc4<A, T1, T2, T3, T4> = (arg1: T1, arg2: T2, arg3: T3, arg4: T4, | ||
action: A) => any; | ||
type HelperFunc5<A, T1, T2, T3, T4, T5> = (arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5, | ||
action: A) => any; | ||
type HelperFunc6Rest<A, T1, T2, T3, T4, T5, T6> = ( | ||
arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5, arg6: T6, | ||
arg7: any, ...rest: any[]) => any; | ||
export function takeEvery<T>( | ||
/** | ||
* You can also pass in a channel as argument and the behaviour is the same as | ||
* `throttle(ms, pattern, saga, ...args)`. | ||
*/ | ||
export function throttle<T>(ms: number, channel: TakeableChannel<T>, worker: (item: T) => any): ForkEffect | ||
export function throttle<T, Fn extends (...args: any[]) => any>( | ||
ms: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc0<T>): ForkEffect; | ||
export function takeEvery<T, T1>( | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc1<T, T1>, | ||
arg1: T1): ForkEffect; | ||
export function takeEvery<T, T1, T2>( | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc2<T, T1, T2>, | ||
arg1: T1, arg2: T2): ForkEffect; | ||
export function takeEvery<T, T1, T2, T3>( | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc3<T, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): ForkEffect; | ||
export function takeEvery<T, T1, T2, T3, T4>( | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc4<T, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): ForkEffect; | ||
export function takeEvery<T, T1, T2, T3, T4, T5>( | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc5<T, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): ForkEffect; | ||
export function takeEvery<T, T1, T2, T3, T4, T5, T6>( | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc6Rest<T, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): ForkEffect; | ||
worker: Fn, | ||
...args: HelperWorkerParameters<T, Fn> | ||
): ForkEffect | ||
export function takeEvery<A extends Action>( | ||
/** | ||
* Spawns a `saga` on an action dispatched to the Store that matches `pattern`. | ||
* Saga will be called after it stops taking `pattern` actions for `ms` | ||
* milliseconds. Purpose of this is to prevent calling saga until the actions | ||
* are settled off. | ||
* | ||
* #### Example | ||
* | ||
* In the following example, we create a basic task `fetchAutocomplete`. We use | ||
* `debounce` to delay calling `fetchAutocomplete` saga until we stop receive | ||
* any `FETCH_AUTOCOMPLETE` events for at least `1000` ms. | ||
* | ||
* import { call, put, debounce } from `redux-saga/effects` | ||
* | ||
* function* fetchAutocomplete(action) { | ||
* const autocompleteProposals = yield call(Api.fetchAutocomplete, action.text) | ||
* yield put({type: 'FETCHED_AUTOCOMPLETE_PROPOSALS', proposals: autocompleteProposals}) | ||
* } | ||
* | ||
* function* debounceAutocomplete() { | ||
* yield debounce(1000, 'FETCH_AUTOCOMPLETE', fetchAutocomplete) | ||
* } | ||
* | ||
* #### Notes | ||
* | ||
* `debounce` is a high-level API built using `take`, `delay` and `fork`. Here | ||
* is how the helper could be implemented using the low-level Effects | ||
* | ||
* const debounce = (ms, pattern, task, ...args) => fork(function*() { | ||
* while (true) { | ||
* let action = yield take(pattern) | ||
* | ||
* while (true) { | ||
* const { debounced, _action } = yield race({ | ||
* debounced: delay(ms), | ||
* _action: take(pattern) | ||
* }) | ||
* | ||
* if (debounced) { | ||
* yield fork(worker, ...args, action) | ||
* break | ||
* } | ||
* | ||
* action = _action | ||
* } | ||
* } | ||
* }) | ||
* | ||
* @param ms defines how many milliseconds should elapse since the last time | ||
* `pattern` action was fired to call the `saga` | ||
* @param pattern for more information see docs for `take(pattern)` | ||
* @param saga a Generator function | ||
* @param args arguments to be passed to the started task. `debounce` will add | ||
* the incoming action to the argument list (i.e. the action will be the last | ||
* argument provided to `saga`) | ||
*/ | ||
export function debounce<A extends Action>( | ||
ms: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc0<A>): ForkEffect; | ||
export function takeEvery<A extends Action, T1>( | ||
worker: (action: A) => any, | ||
): ForkEffect | ||
export function debounce<A extends Action, Fn extends (...args: any[]) => any>( | ||
ms: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc1<A, T1>, | ||
arg1: T1): ForkEffect; | ||
export function takeEvery<A extends Action, T1, T2>( | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc2<A, T1, T2>, | ||
arg1: T1, arg2: T2): ForkEffect; | ||
export function takeEvery<A extends Action, T1, T2, T3>( | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc3<A, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): ForkEffect; | ||
export function takeEvery<A extends Action, T1, T2, T3, T4>( | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc4<A, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): ForkEffect; | ||
export function takeEvery<A extends Action, T1, T2, T3, T4, T5>( | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc5<A, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): ForkEffect; | ||
export function takeEvery<A extends Action, T1, T2, T3, T4, T5, T6>( | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc6Rest<A, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): ForkEffect; | ||
worker: Fn, | ||
...args: HelperWorkerParameters<A, Fn> | ||
): ForkEffect | ||
/** | ||
* You can also pass in a channel as argument and the behaviour is the same as | ||
* `debounce(ms, pattern, saga, ...args)`. | ||
*/ | ||
export function debounce<T>(ms: number, channel: TakeableChannel<T>, worker: (item: T) => any): ForkEffect | ||
export function debounce<T, Fn extends (...args: any[]) => any>( | ||
ms: number, | ||
channel: TakeableChannel<T>, | ||
worker: Fn, | ||
...args: HelperWorkerParameters<T, Fn> | ||
): ForkEffect | ||
export const takeLatest: typeof takeEvery; | ||
export const takeLeading: typeof takeEvery; | ||
export function throttle<A extends Action>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc0<A>): ForkEffect; | ||
export function throttle<A extends Action, T1>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc1<A, T1>, | ||
arg1: T1): ForkEffect; | ||
export function throttle<A extends Action, T1, T2>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc2<A, T1, T2>, | ||
arg1: T1, arg2: T2): ForkEffect; | ||
export function throttle<A extends Action, T1, T2, T3>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc3<A, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): ForkEffect; | ||
export function throttle<A extends Action, T1, T2, T3, T4>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc4<A, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): ForkEffect; | ||
export function throttle<A extends Action, T1, T2, T3, T4, T5>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc5<A, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): ForkEffect; | ||
export function throttle<A extends Action, T1, T2, T3, T4, T5, T6>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc6Rest<A, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): ForkEffect; | ||
export function debounce<A extends Action>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc0<A>): ForkEffect; | ||
export function debounce<A extends Action, T1>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc1<A, T1>, | ||
arg1: T1): ForkEffect; | ||
export function debounce<A extends Action, T1, T2>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc2<A, T1, T2>, | ||
arg1: T1, arg2: T2): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc3<A, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3, T4>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc4<A, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3, T4, T5>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc5<A, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3, T4, T5, T6>( | ||
ms: number, pattern: ActionPattern<A>, | ||
worker: HelperFunc6Rest<A, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): ForkEffect; | ||
export function delay<T>(ms: number, val?: T): CallEffect; | ||
export function retry<R>( | ||
/** | ||
* Creates an Effect description that instructs the middleware to call the | ||
* function `fn` with `args` as arguments. In case of failure will try to make | ||
* another call after `delay` milliseconds, if a number of attempts < `maxTries`. | ||
* | ||
* #### Example | ||
* | ||
* In the following example, we create a basic task `retrySaga`. We use `retry` | ||
* to try to fetch our API 3 times with 10 second interval. If `request` fails | ||
* first time than `retry` will call `request` one more time while calls count | ||
* less than 3. | ||
* | ||
* import { put, retry } from 'redux-saga/effects' | ||
* import { request } from 'some-api'; | ||
* | ||
* function* retrySaga(data) { | ||
* try { | ||
* const SECOND = 1000 | ||
* const response = yield retry(3, 10 * SECOND, request, data) | ||
* yield put({ type: 'REQUEST_SUCCESS', payload: response }) | ||
* } catch(error) { | ||
* yield put({ type: 'REQUEST_FAIL', payload: { error } }) | ||
* } | ||
* } | ||
* | ||
* @param maxTries maximum calls count. | ||
* @param delay length of a time window in milliseconds between `fn` calls. | ||
* @param fn A Generator function, or normal function which either returns a | ||
* Promise as a result, or any other value. | ||
* @param args An array of values to be passed as arguments to `fn` | ||
*/ | ||
export function retry<Fn extends (...args: any[]) => any>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func0<R> | ||
fn: Fn, | ||
...args: Parameters<Fn> | ||
): CallEffect | ||
export function retry<R, T1>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func1<R, T1>, | ||
arg1: T1 | ||
): CallEffect | ||
/** | ||
* Creates an Effect description that instructs the middleware to run multiple | ||
* Effects in parallel and wait for all of them to complete. It's quite the | ||
* corresponding API to standard | ||
* [`Promise#all`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). | ||
* | ||
* #### Example | ||
* | ||
* The following example runs two blocking calls in parallel: | ||
* | ||
* import { fetchCustomers, fetchProducts } from './path/to/api' | ||
* import { all, call } from `redux-saga/effects` | ||
* | ||
* function* mySaga() { | ||
* const [customers, products] = yield all([ | ||
* call(fetchCustomers), | ||
* call(fetchProducts) | ||
* ]) | ||
* } | ||
*/ | ||
export function all<T>(effects: T[]): AllEffect<T> | ||
/** | ||
* The same as `all([...effects])` but let's you to pass in a dictionary object | ||
* of effects with labels, just like `race(effects)` | ||
* | ||
* @param effects a dictionary Object of the form {label: effect, ...} | ||
*/ | ||
export function all<T>(effects: { [key: string]: T }): AllEffect<T> | ||
export function retry<R, T1, T2>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func2<R, T1, T2>, | ||
arg1: T1, arg2: T2, | ||
): CallEffect | ||
export type AllEffect<T> = CombinatorEffect<'ALL', T> | ||
export function retry<R, T1, T2, T3>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func3<R, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3, | ||
): CallEffect | ||
export type AllEffectDescriptor<T> = CombinatorEffectDescriptor<T> | ||
export function retry<R, T1, T2, T3, T4>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func4<R, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, | ||
): CallEffect | ||
/** | ||
* Creates an Effect description that instructs the middleware to run a *Race* | ||
* between multiple Effects (this is similar to how | ||
* [`Promise.race([...])`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/race) | ||
* behaves). | ||
* | ||
* | ||
* #### Example | ||
* | ||
* The following example runs a race between two effects: | ||
* | ||
* 1. A call to a function `fetchUsers` which returns a Promise | ||
* 2. A `CANCEL_FETCH` action which may be eventually dispatched on the Store | ||
* | ||
* | ||
* import { take, call, race } from `redux-saga/effects` | ||
* import fetchUsers from './path/to/fetchUsers' | ||
* | ||
* function* fetchUsersSaga() { | ||
* const { response, cancel } = yield race({ | ||
* response: call(fetchUsers), | ||
* cancel: take(CANCEL_FETCH) | ||
* }) | ||
* } | ||
* | ||
* If `call(fetchUsers)` resolves (or rejects) first, the result of `race` will | ||
* be an object with a single keyed object `{response: result}` where `result` | ||
* is the resolved result of `fetchUsers`. | ||
* | ||
* If an action of type `CANCEL_FETCH` is dispatched on the Store before | ||
* `fetchUsers` completes, the result will be a single keyed object | ||
* `{cancel: action}`, where action is the dispatched action. | ||
* | ||
* #### Notes | ||
* | ||
* When resolving a `race`, the middleware automatically cancels all the losing | ||
* Effects. | ||
* | ||
* @param effects a dictionary Object of the form {label: effect, ...} | ||
*/ | ||
export function race<T>(effects: { [key: string]: T }): RaceEffect<T> | ||
/** | ||
* The same as `race(effects)` but lets you pass in an array of effects. | ||
*/ | ||
export function race<T>(effects: T[]): RaceEffect<T> | ||
export function retry<R, T1, T2, T3, T4, T5>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func5<R, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, | ||
): CallEffect | ||
export type RaceEffect<T> = CombinatorEffect<'RACE', T> | ||
export function retry<R, T1, T2, T3, T4, T5, T6>( | ||
maxTries: number, | ||
delayLength: number, | ||
fn: Func6Rest<R, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, ...rest: any[] | ||
): CallEffect | ||
export type RaceEffectDescriptor<T> = CombinatorEffectDescriptor<T> | ||
export function debounce<A extends Action>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc0<A> | ||
): ForkEffect; | ||
export function debounce<A extends Action, T1>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc1<A, T1>, | ||
arg1: T1 | ||
): ForkEffect; | ||
export function debounce<A extends Action, T1, T2>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc2<A, T1, T2>, | ||
arg1: T1, arg2: T2 | ||
): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc3<A, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3 | ||
): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3, T4>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc4<A, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4 | ||
): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3, T4, T5>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc5<A, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5 | ||
): ForkEffect; | ||
export function debounce<A extends Action, T1, T2, T3, T4, T5, T6>( | ||
delayLength: number, | ||
pattern: ActionPattern<A>, | ||
worker: HelperFunc6Rest<A, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[] | ||
): ForkEffect; | ||
export function debounce<T>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc0<T> | ||
): ForkEffect; | ||
export function debounce<T, T1>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc1<T, T1>, | ||
arg1: T1 | ||
): ForkEffect; | ||
export function debounce<T, T1, T2>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc2<T, T1, T2>, | ||
arg1: T1, arg2: T2 | ||
): ForkEffect; | ||
export function debounce<T, T1, T2, T3>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc3<T, T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3 | ||
): ForkEffect; | ||
export function debounce<T, T1, T2, T3, T4>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc4<T, T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4 | ||
): ForkEffect; | ||
export function debounce<T, T1, T2, T3, T4, T5>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc5<T, T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5 | ||
): ForkEffect; | ||
export function debounce<T, T1, T2, T3, T4, T5, T6>( | ||
delayLength: number, | ||
channel: TakeableChannel<T>, | ||
worker: HelperFunc6Rest<T, T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[] | ||
): ForkEffect; | ||
export const effectTypes: { | ||
TAKE: 'TAKE', | ||
PUT: 'PUT', | ||
ALL: 'ALL', | ||
RACE: 'RACE', | ||
CALL: 'CALL', | ||
CPS: 'CPS', | ||
FORK: 'FORK', | ||
JOIN: 'JOIN', | ||
CANCEL: 'CANCEL', | ||
SELECT: 'SELECT', | ||
ACTION_CHANNEL: 'ACTION_CHANNEL', | ||
CANCELLED: 'CANCELLED', | ||
FLUSH: 'FLUSH', | ||
GET_CONTEXT: 'GET_CONTEXT', | ||
SET_CONTEXT: 'SET_CONTEXT', | ||
} | ||
/** | ||
* [H, ...T] -> T | ||
*/ | ||
export type Tail<L extends any[]> = ((...l: L) => any) extends ((h: any, ...t: infer T) => any) ? T : never | ||
/** | ||
* [...A, B] -> A | ||
*/ | ||
export type AllButLast<L extends any[]> = Reverse<Tail<Reverse<L>>> |
484
index.d.ts
@@ -1,208 +0,362 @@ | ||
import {Action, Middleware} from "redux"; | ||
import {Effect, ForkEffect} from "./effects"; | ||
import { Action, Middleware } from 'redux' | ||
import { Saga, Buffer, Channel, END, Predicate, SagaIterator, Task } from '@redux-saga/types' | ||
import { ForkEffect } from './effects' | ||
export {Effect}; | ||
export { Saga, SagaIterator, Buffer, Channel, Task } | ||
/** | ||
* Annotate return type of generators with `SagaIterator` to get strict | ||
* type-checking of yielded effects. | ||
* Used by the middleware to dispatch monitoring events. Actually the middleware | ||
* dispatches 6 events: | ||
* | ||
* - When a root saga is started (via `runSaga` or `sagaMiddleware.run`) the | ||
* middleware invokes `sagaMonitor.rootSagaStarted` | ||
* | ||
* - When an effect is triggered (via `yield someEffect`) the middleware invokes | ||
* `sagaMonitor.effectTriggered` | ||
* | ||
* - If the effect is resolved with success the middleware invokes | ||
* `sagaMonitor.effectResolved` | ||
* | ||
* - If the effect is rejected with an error the middleware invokes | ||
* `sagaMonitor.effectRejected` | ||
* | ||
* - If the effect is cancelled the middleware invokes | ||
* `sagaMonitor.effectCancelled` | ||
* | ||
* - Finally, the middleware invokes `sagaMonitor.actionDispatched` when a Redux | ||
* action is dispatched. | ||
*/ | ||
export type SagaIterator = IterableIterator<Effect>; | ||
export interface SagaMonitor { | ||
/** | ||
* @param effectId Unique ID assigned to this root saga execution | ||
* @param saga The generator function that starts to run | ||
* @param args The arguments passed to the generator function | ||
*/ | ||
rootSagaStarted?(options: { effectId: number; saga: Saga; args: any[] }): void | ||
/** | ||
* @param effectId Unique ID assigned to the yielded effect | ||
* @param parentEffectId ID of the parent Effect. In the case of a `race` or | ||
* `parallel` effect, all effects yielded inside will have the direct | ||
* race/parallel effect as a parent. In case of a top-level effect, the | ||
* parent will be the containing Saga | ||
* @param label In case of a `race`/`all` effect, all child effects will be | ||
* assigned as label the corresponding keys of the object passed to | ||
* `race`/`all` | ||
* @param effect The yielded effect itself | ||
*/ | ||
effectTriggered?(options: { effectId: number; parentEffectId: number; label?: string; effect: any }): void | ||
/** | ||
* @param effectId The ID of the yielded effect | ||
* @param result The result of the successful resolution of the effect. In | ||
* case of `fork` or `spawn` effects, the result will be a `Task` object. | ||
*/ | ||
effectResolved?(effectId: number, result: any): void | ||
/** | ||
* @param effectId The ID of the yielded effect | ||
* @param error Error raised with the rejection of the effect | ||
*/ | ||
effectRejected?(effectId: number, error: any): void | ||
/** | ||
* @param effectId The ID of the yielded effect | ||
*/ | ||
effectCancelled?(effectId: number): void | ||
/** | ||
* @param action The dispatched Redux action. If the action was dispatched by | ||
* a Saga then the action will have a property `SAGA_ACTION` set to true | ||
* (`SAGA_ACTION` can be imported from `redux-saga/utils`). | ||
*/ | ||
actionDispatched?(action: Action): void | ||
} | ||
type Saga0 = () => Iterator<any>; | ||
type Saga1<T1> = (arg1: T1) => Iterator<any>; | ||
type Saga2<T1, T2> = (arg1: T1, arg2: T2) => Iterator<any>; | ||
type Saga3<T1, T2, T3> = (arg1: T1, arg2: T2, arg3: T3) => Iterator<any>; | ||
type Saga4<T1, T2, T3, T4> = | ||
(arg1: T1, arg2: T2, arg3: T3, arg4: T4) => Iterator<any>; | ||
type Saga5<T1, T2, T3, T4, T5> = | ||
(arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => Iterator<any>; | ||
type Saga6Rest<T1, T2, T3, T4, T5, T6> = | ||
(arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]) => Iterator<any>; | ||
/** | ||
* Creates a Redux middleware and connects the Sagas to the Redux Store | ||
* | ||
* #### Example | ||
* | ||
* Below we will create a function `configureStore` which will enhance the Store | ||
* with a new method `runSaga`. Then in our main module, we will use the method | ||
* to start the root Saga of the application. | ||
* | ||
* **configureStore.js** | ||
* | ||
* import createSagaMiddleware from 'redux-saga' | ||
* import reducer from './path/to/reducer' | ||
* | ||
* export default function configureStore(initialState) { | ||
* // Note: passing middleware as the last argument to createStore requires redux@>=3.1.0 | ||
* const sagaMiddleware = createSagaMiddleware() | ||
* return { | ||
* ...createStore(reducer, initialState, applyMiddleware(... other middleware ..., sagaMiddleware)), | ||
* runSaga: sagaMiddleware.run | ||
* } | ||
* } | ||
* | ||
* **main.js** | ||
* | ||
* import configureStore from './configureStore' | ||
* import rootSaga from './sagas' | ||
* // ... other imports | ||
* | ||
* const store = configureStore() | ||
* store.runSaga(rootSaga) | ||
* | ||
* @param options A list of options to pass to the middleware | ||
*/ | ||
export default function createSagaMiddleware<C extends object>(options?: SagaMiddlewareOptions<C>): SagaMiddleware<C> | ||
export interface SagaMiddlewareOptions<C extends object = {}> { | ||
/** | ||
* Initial value of the saga's context. | ||
*/ | ||
context?: C | ||
/** | ||
* If a Saga Monitor is provided, the middleware will deliver monitoring | ||
* events to the monitor. | ||
*/ | ||
sagaMonitor?: SagaMonitor | ||
/** | ||
* If provided, the middleware will call it with uncaught errors from Sagas. | ||
* useful for sending uncaught exceptions to error tracking services. | ||
*/ | ||
onError?(error: Error, errorInfo: ErrorInfo): void | ||
/** | ||
* Allows you to intercept any effect, resolve it on your own and pass to the | ||
* next middleware. | ||
*/ | ||
effectMiddlewares?: EffectMiddleware[] | ||
} | ||
export interface Monitor { | ||
effectTriggered?(desc: { | ||
effectId: number; | ||
parentEffectId: number; | ||
label?: string; | ||
root?: boolean; | ||
effect: Effect; | ||
}): void; | ||
export interface SagaMiddleware<C extends object = {}> extends Middleware { | ||
/** | ||
* Dynamically run `saga`. Can be used to run Sagas **only after** the | ||
* `applyMiddleware` phase. | ||
* | ||
* The method returns a `Task` descriptor. | ||
* | ||
* #### Notes | ||
* | ||
* `saga` must be a function which returns a [Generator | ||
* Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator). | ||
* The middleware will then iterate over the Generator and execute all yielded | ||
* Effects. | ||
* | ||
* `saga` may also start other sagas using the various Effects provided by the | ||
* library. The iteration process described below is also applied to all child | ||
* sagas. | ||
* | ||
* In the first iteration, the middleware invokes the `next()` method to | ||
* retrieve the next Effect. The middleware then executes the yielded Effect | ||
* as specified by the Effects API below. Meanwhile, the Generator will be | ||
* suspended until the effect execution terminates. Upon receiving the result | ||
* of the execution, the middleware calls `next(result)` on the Generator | ||
* passing it the retrieved result as an argument. This process is repeated | ||
* until the Generator terminates normally or by throwing some error. | ||
* | ||
* If the execution results in an error (as specified by each Effect creator) | ||
* then the `throw(error)` method of the Generator is called instead. If the | ||
* Generator function defines a `try/catch` surrounding the current yield | ||
* instruction, then the `catch` block will be invoked by the underlying | ||
* Generator runtime. The runtime will also invoke any corresponding finally | ||
* block. | ||
* | ||
* In the case a Saga is cancelled (either manually or using the provided | ||
* Effects), the middleware will invoke `return()` method of the Generator. | ||
* This will cause the Generator to skip directly to the finally block. | ||
* | ||
* @param saga a Generator function | ||
* @param args arguments to be provided to `saga` | ||
*/ | ||
run<S extends Saga>(saga: S, ...args: Parameters<S>): Task | ||
effectResolved?(effectId: number, res: any): void; | ||
effectRejected?(effectId: number, err: any): void; | ||
effectCancelled?(effectId: number): void; | ||
actionDispatched?<A extends Action>(action: A): void; | ||
setContext(props: Partial<C>): void | ||
} | ||
export interface EffectMiddleware { | ||
(next: (effect: any) => void): (effect: any) => void; | ||
(next: (effect: any) => void): (effect: any) => void | ||
} | ||
/** | ||
* Allows starting sagas outside the Redux middleware environment. Useful if you | ||
* want to connect a Saga to external input/output, other than store actions. | ||
* | ||
* `runSaga` returns a Task object. Just like the one returned from a `fork` | ||
* effect. | ||
*/ | ||
export function runSaga<Action, State, S extends Saga>( | ||
options: RunSagaOptions<Action, State>, | ||
saga: S, | ||
...args: Parameters<S> | ||
): Task | ||
export interface SagaMiddleware<C = {}> extends Middleware { | ||
run(saga: Saga0): Task; | ||
run<T1>(saga: Saga1<T1>, | ||
arg1: T1): Task; | ||
run<T1, T2>(saga: Saga2<T1, T2>, | ||
arg1: T1, arg2: T2): Task; | ||
run<T1, T2, T3>(saga: Saga3<T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): Task; | ||
run<T1, T2, T3, T4>(saga: Saga4<T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): Task; | ||
run<T1, T2, T3, T4, T5>(saga: Saga5<T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5): Task; | ||
run<T1, T2, T3, T4, T5, T6>(saga: Saga6Rest<T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, | ||
arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): Task; | ||
setContext(props: Partial<C>): void; | ||
interface ErrorInfo { | ||
sagaStack: string | ||
} | ||
export type Logger = (level: string, ...args: any[]) => void; | ||
export type Emit<T> = (input: T) => void; | ||
export interface SagaMiddlewareOptions<C extends object = {}> { | ||
context?: C; | ||
sagaMonitor?: Monitor; | ||
logger?: Logger; | ||
onError?(error: Error): void; | ||
effectMiddlewares?: EffectMiddleware[]; | ||
emitter?(emit: Emit<Action>): Emit<any>; | ||
} | ||
export default function sagaMiddlewareFactory<C extends object>( | ||
options?: SagaMiddlewareOptions<C>, | ||
): SagaMiddleware<C>; | ||
/** | ||
* The `{subscribe, dispatch}` is used to fulfill `take` and `put` Effects. This | ||
* defines the Input/Output interface of the Saga. | ||
* | ||
* `subscribe` is used to fulfill `take(PATTERN)` effects. It must call | ||
* `callback` every time it has an input to dispatch (e.g. on every mouse click | ||
* if the Saga is connected to DOM click events). Each time `subscribe` emits an | ||
* input to its callbacks, if the Saga is blocked on a `take` effect, and if the | ||
* take pattern matches the currently incoming input, the Saga is resumed with | ||
* that input. | ||
* | ||
* `dispatch` is used to fulfill `put` effects. Each time the Saga emits a | ||
* `yield put(output)`, `dispatch` is invoked with output. | ||
*/ | ||
export interface RunSagaOptions<A, S> { | ||
channel?: PredicateTakeableChannel<A>; | ||
dispatch?(input: A): any; | ||
getState?(): S; | ||
context?: object; | ||
sagaMonitor?: Monitor; | ||
logger?: Logger; | ||
effectMiddlewares?: EffectMiddleware[]; | ||
onError?(error: Error): void; | ||
/** | ||
* See docs for `channel` | ||
*/ | ||
channel?: PredicateTakeableChannel<A> | ||
/** | ||
* Used to fulfill `put` effects. | ||
* | ||
* @param output argument provided by the Saga to the `put` Effect | ||
*/ | ||
dispatch?(output: A): any | ||
/** | ||
* Used to fulfill `select` and `getState` effects | ||
*/ | ||
getState?(): S | ||
/** | ||
* See docs for `createSagaMiddleware(options)` | ||
*/ | ||
sagaMonitor?: SagaMonitor | ||
/** | ||
* See docs for `createSagaMiddleware(options)` | ||
*/ | ||
onError?(error: Error, errorInfo: ErrorInfo): void | ||
/** | ||
* See docs for `createSagaMiddleware(options)` | ||
*/ | ||
context?: object | ||
/** | ||
* See docs for `createSagaMiddleware(options)` | ||
*/ | ||
effectMiddlewares?: EffectMiddleware[] | ||
} | ||
export function runSaga<A, S>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga0): Task; | ||
export function runSaga<A, S, T1>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga1<T1>, | ||
arg1: T1): Task; | ||
export function runSaga<A, S, T1, T2>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga2<T1, T2>, | ||
arg1: T1, arg2: T2): Task; | ||
export function runSaga<A, S, T1, T2, T3>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga3<T1, T2, T3>, | ||
arg1: T1, arg2: T2, arg3: T3): Task; | ||
export function runSaga<A, S, T1, T2, T3, T4>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga4<T1, T2, T3, T4>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4): Task; | ||
export function runSaga<A, S, T1, T2, T3, T4, T5>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga5<T1, T2, T3, T4, T5>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5): Task; | ||
export function runSaga<A, S, T1, T2, T3, T4, T5, T6>( | ||
options: RunSagaOptions<A, S>, | ||
saga: Saga6Rest<T1, T2, T3, T4, T5, T6>, | ||
arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, | ||
...rest: any[]): Task; | ||
export const CANCEL: string | ||
export const END: END | ||
export type END = END | ||
export const CANCEL: string; | ||
export type END = {type: '@@redux-saga/CHANNEL_END'}; | ||
export const END: END; | ||
export type Predicate<T> = (arg: T) => boolean; | ||
export interface Task { | ||
isRunning(): boolean; | ||
isCancelled(): boolean; | ||
result<T = any>(): T | undefined; | ||
error(): any | undefined; | ||
toPromise<T = any>(): Promise<T>; | ||
cancel(): void; | ||
setContext<C extends object>(props: Partial<C>): void; | ||
} | ||
export interface Buffer<T> { | ||
isEmpty(): boolean; | ||
put(message: T): void; | ||
take(): T | undefined; | ||
flush(): T[]; | ||
} | ||
export interface TakeableChannel<T> { | ||
take(cb: (message: T | END) => void): void; | ||
take(cb: (message: T | END) => void): void | ||
} | ||
export interface PuttableChannel<T> { | ||
put(message: T | END): void; | ||
put(message: T | END): void | ||
} | ||
export interface FlushableChannel<T> { | ||
flush(cb: (items: T[] | END) => void): void; | ||
flush(cb: (items: T[] | END) => void): void | ||
} | ||
export interface Channel<T> { | ||
take(cb: (message: T | END) => void): void; | ||
put(message: T | END): void; | ||
flush(cb: (items: T[] | END) => void): void; | ||
close(): void; | ||
} | ||
/** | ||
* A factory method that can be used to create Channels. You can optionally pass | ||
* it a buffer to control how the channel buffers the messages. | ||
* | ||
* By default, if no buffer is provided, the channel will queue incoming | ||
* messages up to 10 until interested takers are registered. The default | ||
* buffering will deliver message using a FIFO strategy: a new taker will be | ||
* delivered the oldest message in the buffer. | ||
*/ | ||
export function channel<T>(buffer?: Buffer<T>): Channel<T> | ||
export function channel<T>(buffer?: Buffer<T>): Channel<T>; | ||
/** | ||
* Creates channel that will subscribe to an event source using the `subscribe` | ||
* method. Incoming events from the event source will be queued in the channel | ||
* until interested takers are registered. | ||
* | ||
* To notify the channel that the event source has terminated, you can notify | ||
* the provided subscriber with an `END` | ||
* | ||
* #### Example | ||
* | ||
* In the following example we create an event channel that will subscribe to a | ||
* `setInterval` | ||
* | ||
* const countdown = (secs) => { | ||
* return eventChannel(emitter => { | ||
* const iv = setInterval(() => { | ||
* console.log('countdown', secs) | ||
* secs -= 1 | ||
* if (secs > 0) { | ||
* emitter(secs) | ||
* } else { | ||
* emitter(END) | ||
* clearInterval(iv) | ||
* console.log('countdown terminated') | ||
* } | ||
* }, 1000); | ||
* return () => { | ||
* clearInterval(iv) | ||
* console.log('countdown cancelled') | ||
* } | ||
* } | ||
* ) | ||
* } | ||
* | ||
* @param subscribe used to subscribe to the underlying event source. The | ||
* function must return an unsubscribe function to terminate the subscription. | ||
* @param buffer optional Buffer object to buffer messages on this channel. If | ||
* not provided, messages will not be buffered on this channel. | ||
* @param optional predicate function (`any => Boolean`) to filter incoming | ||
* messages. Only messages accepted by the matcher will be put on the channel. | ||
*/ | ||
export function eventChannel<T>(subscribe: Subscribe<T>, buffer?: Buffer<T>, matcher?: Predicate<T>): EventChannel<T> | ||
export type Subscribe<T> = (cb: (input: T | END) => void) => Unsubscribe | ||
export type Unsubscribe = () => void | ||
export interface EventChannel<T> { | ||
take(cb: (message: T | END) => void): void; | ||
flush(cb: (items: T[] | END) => void): void; | ||
close(): void; | ||
take(cb: (message: T | END) => void): void | ||
flush(cb: (items: T[] | END) => void): void | ||
close(): void | ||
} | ||
export type Unsubscribe = () => void; | ||
export type Subscribe<T> = (cb: (input: T | END) => void) => Unsubscribe; | ||
export function eventChannel<T>(subscribe: Subscribe<T>, | ||
buffer?: Buffer<T>): EventChannel<T>; | ||
export interface PredicateTakeableChannel<T> { | ||
take(cb: (message: T | END) => void, matcher?: Predicate<T>): void; | ||
take(cb: (message: T | END) => void, matcher?: Predicate<T>): void | ||
} | ||
export interface MulticastChannel<T> { | ||
take(cb: (message: T | END) => void, matcher?: Predicate<T>): void; | ||
put(message: T | END): void; | ||
close(): void; | ||
take(cb: (message: T | END) => void, matcher?: Predicate<T>): void | ||
put(message: T | END): void | ||
close(): void | ||
} | ||
export function multicastChannel<T>(): MulticastChannel<T>; | ||
export function stdChannel<T>(): MulticastChannel<T>; | ||
export function multicastChannel<T>(): MulticastChannel<T> | ||
export function stdChannel<T>(): MulticastChannel<T> | ||
export function detach(forkEffect: ForkEffect): ForkEffect; | ||
export function detach(forkEffect: ForkEffect): ForkEffect | ||
import * as effects from './effects'; | ||
import * as utils from './utils'; | ||
export {effects, utils}; | ||
/** | ||
* Provides some common buffers | ||
*/ | ||
export const buffers: { | ||
none<T>(): Buffer<T>; | ||
fixed<T>(limit?: number): Buffer<T>; | ||
dropping<T>(limit?: number): Buffer<T>; | ||
sliding<T>(limit?: number): Buffer<T>; | ||
expanding<T>(limit?: number): Buffer<T>; | ||
}; | ||
/** | ||
* No buffering, new messages will be lost if there are no pending takers | ||
*/ | ||
none<T>(): Buffer<T> | ||
/** | ||
* New messages will be buffered up to `limit`. Overflow will raise an Error. | ||
* Omitting a `limit` value will result in a limit of 10. | ||
*/ | ||
fixed<T>(limit?: number): Buffer<T> | ||
/** | ||
* Like `fixed` but Overflow will cause the buffer to expand dynamically. | ||
*/ | ||
expanding<T>(limit?: number): Buffer<T> | ||
/** | ||
* Same as `fixed` but Overflow will silently drop the messages. | ||
*/ | ||
dropping<T>(limit?: number): Buffer<T> | ||
/** | ||
* Same as `fixed` but Overflow will insert the new message at the end and | ||
* drop the oldest message in the buffer. | ||
*/ | ||
sliding<T>(limit?: number): Buffer<T> | ||
} |
{ | ||
"name": "redux-saga", | ||
"version": "1.0.0-beta.3", | ||
"version": "1.0.0-rc.0", | ||
"description": "Saga middleware for Redux to handle Side Effects", | ||
@@ -11,3 +11,2 @@ "main": "./dist/redux-saga-core.cjs.js", | ||
"effects", | ||
"utils", | ||
"*.d.ts" | ||
@@ -21,6 +20,6 @@ ], | ||
"prebuild": "npm run clean", | ||
"build": "rollup -c && node ./scripts/createProxyCjsEntries.js", | ||
"build": "rollup -c", | ||
"postbuild": "node ./scripts/createProxyCjsEntries.js", | ||
"prepare": "npm run build", | ||
"prepush": "npm run test", | ||
"preversion": "npm run test && npm run prepare", | ||
"preversion": "npm test", | ||
"release:patch": "npm version patch && npm publish && git push --follow-tags", | ||
@@ -42,3 +41,3 @@ "release:minor": "npm version minor && npm publish && git push --follow-tags", | ||
"path": "./dist/redux-saga.min.umd.js", | ||
"maxSize": "7 Kb" | ||
"maxSize": "6.5 Kb" | ||
} | ||
@@ -50,3 +49,4 @@ ], | ||
"Mikhail Shustov <restrry@gmail.com> (https://github.com/restrry)", | ||
"Shi Feichao <842351815@qq.com> (https://github.com/shinima)" | ||
"Shi Feichao <842351815@qq.com> (https://github.com/shinima)", | ||
"Daniel Lytkin <dan.lytkin@gmail.com (https://github.com/aikoven)" | ||
], | ||
@@ -60,7 +60,9 @@ "license": "MIT", | ||
"@babel/runtime": "^7.0.0", | ||
"@redux-saga/deferred": "^1.0.0-beta.3", | ||
"@redux-saga/delay-p": "^1.0.0-beta.3", | ||
"@redux-saga/is": "^1.0.0-beta.3", | ||
"@redux-saga/symbols": "^1.0.0-beta.3", | ||
"redux": ">=0.10 <5" | ||
"@redux-saga/deferred": "^1.0.0-rc.0", | ||
"@redux-saga/delay-p": "^1.0.0-rc.0", | ||
"@redux-saga/is": "^1.0.0-rc.0", | ||
"@redux-saga/symbols": "^1.0.0-rc.0", | ||
"@redux-saga/types": "^1.0.0-rc.0", | ||
"redux": ">=0.10 <5", | ||
"typescript-tuple": "^2.1.0" | ||
}, | ||
@@ -79,3 +81,2 @@ "devDependencies": { | ||
"lerna-alias": "^3.0.2", | ||
"lolex": "^1.5.2", | ||
"mitt": "^1.1.2", | ||
@@ -89,3 +90,3 @@ "rimraf": "^2.4.3", | ||
"rollup-plugin-uglify": "^2.0.1", | ||
"typescript": "^2.6.2", | ||
"typescript": "^3.2.1", | ||
"typings-tester": "^0.2.2" | ||
@@ -92,0 +93,0 @@ }, |
Sorry, the diff of this file is too big to display
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
354202
21
10450
41
8
17
+ Addedtypescript-tuple@^2.1.0
+ Addedtypescript-compare@0.0.2(transitive)
+ Addedtypescript-logic@0.0.0(transitive)
+ Addedtypescript-tuple@2.2.1(transitive)
Updated@redux-saga/is@^1.0.0-rc.0