raiden-ts
Version:
Raiden Light Client Typescript/Javascript SDK
242 lines • 10.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createReducer = exports.asyncActionToPromise = exports.isConfirmationResponseOf = exports.isResponseOf = exports.createAsyncAction = exports.isActionOf = exports.createAction = void 0;
/* eslint-disable @typescript-eslint/no-explicit-any */
const t = __importStar(require("io-ts"));
const isMatchWith_1 = __importDefault(require("lodash/isMatchWith"));
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const utils_1 = require("../utils");
const error_1 = require("../utils/error");
const types_1 = require("./types");
/**
* @param args - Args params
* @returns action creator
*/
function createAction(...args) {
const [type, payloadCodec, metaCodec, error] = args;
const codec = t.readonly(t.type({
type: t.literal(type),
...(payloadCodec ? { payload: payloadCodec } : null),
...(metaCodec ? { meta: metaCodec } : null),
...(error ? { error: t.literal(true) } : null),
}));
const is = process.env['NODE_ENV'] === 'development'
? (action) => codec.is(action)
: (action) => action?.['type'] === type;
return Object.assign(function actionFactory(payload, meta) {
return {
type,
...(payloadCodec ? { payload } : {}),
...(metaCodec ? { meta } : {}),
...(error ? { error } : {}),
};
}, { type, is, codec, error });
}
exports.createAction = createAction;
/**
* Curried typeguard function (arity=2) which validates 2nd param is of type of some ActionCreators
*
* @param ac - Single or array of ActionCreators
* @param args - if an object is passed, verify it, else returns a function which does
* @returns boolean indicating object is of type of action, if passing 2nd argument,
* or typeguard function
*/
function isActionOf(ac, ...args) {
function _isActionOf(action) {
if (typeof this === 'function')
return this.is(action);
if (Array.isArray(this))
return this.some((a) => _isActionOf.call(a, action));
if (typeof this === 'object')
return _isActionOf.call(Object.values(this), action);
return false;
}
if (args.length > 0)
return _isActionOf.call(ac, args[0]);
return _isActionOf.bind(ac);
}
exports.isActionOf = isActionOf;
/**
* Create a set of async actions
*
* Here, meta is first class citizen, as it's required and what links a request with its responses
* (success or failure).
*
* @param args - Arguments tuple; [meta, type] are required, while [request, success an failure]
* are codecs to be used as payloads for the respective ActionCreators
* @returns Async actions
*/
function createAsyncAction(...args) {
return {
request: createAction(`${args[1]}/request`, args[2], args[0]),
success: createAction(`${args[1]}/success`, args[3], args[0]),
failure: createAction(`${args[1]}/failure`, (args[4] ?? t.unknown), args[0], true),
};
}
exports.createAsyncAction = createAsyncAction;
/**
* Match a passed meta with an action if returns true if metas are from corresponding actions
*
* curried (arity=2) for action passed as 2nd param.
*
* @param meta - meta base for comparison
* @param args - curried args array
* @returns true if metas are compatible, false otherwise
*/
function matchMeta(meta, ...args) {
const _match = (action) =>
// like isEqual, but for BigNumbers, use .eq
(0, isMatchWith_1.default)(action.meta, meta, (objVal, othVal) =>
// any is to avoid lodash's issue with undefined-returning isMatchWithCustomizer cb type
types_1.BigNumberC.is(objVal) && types_1.BigNumberC.is(othVal) ? objVal.eq(othVal) : undefined);
if (args.length)
return _match(args[0]);
return _match;
}
/**
* Given an AsyncActionCreator and a respective 'meta' object, returns a type guard function for
* responses actions (success|failure) matching given 'meta'
*
* This function receives 2-3 params. If it receives 2, it returns the type guard function, to be
* used for filtering. Otherwise, it performs the check on the 3rd param.
*
* @param asyncAction - AsyncActionCreator object
* @param meta - meta object to filter matching actions
* @param args - curried last param
* @returns type guard function to filter deep-equal meta success|failure actions
*/
function isResponseOf(asyncAction, meta, ...args) {
const _isResponseOf = (action) => isActionOf([asyncAction.success, asyncAction.failure], action) && matchMeta(meta, action);
if (args.length)
return _isResponseOf(args[0]);
return _isResponseOf;
}
exports.isResponseOf = isResponseOf;
/**
* Like isResponseOf, but ignores non-confirmed (or removed by a reorg) success action
*
* Confirmable success actions are emitted twice: first with payload.confirmed=undefined, then with
* either confirmed=true, if tx still present after confirmation blocks, or confirmed=false, if tx
* was removed from blockchain by a reorg.
* This curied helper filter function ensures only one of the later causes a positive filter.
*
* @param asyncAction - AsyncActionCreator object
* @param meta - meta object to filter matching actions
* @param args - curried last param
* @returns type guard function to filter deep-equal meta success|failure actions
*/
function isConfirmationResponseOf(asyncAction, meta, ...args) {
/**
* @param action - action to check
* @returns boolean indicating whether object is confirmation
*/
function _isConfirmation(action) {
return typeof action?.['payload']?.['confirmed'] === 'boolean';
}
const _isResponseOf = (action) => isResponseOf(asyncAction, meta, action) &&
(asyncAction.failure.is(action) || _isConfirmation(action));
if (args.length)
return _isResponseOf(args[0]);
return _isResponseOf;
}
exports.isConfirmationResponseOf = isConfirmationResponseOf;
/**
* Watch a stream of actions and resolves on meta-matching success or rejects on failure
*
* @param asyncAction - async actions object to wait for
* @param meta - meta object of a request to wait for the respective response
* @param action$ - actions stream to watch for responses
* @param confirmed - undefined for any response action, false to filter confirmable actions,
* true for confirmed ones
* @returns Promise which rejects with payload in case of failure, or resolves payload otherwise
*/
async function asyncActionToPromise(asyncAction, meta, action$, confirmed) {
return (0, rxjs_1.firstValueFrom)(action$.pipe((0, operators_1.filter)(confirmed
? isConfirmationResponseOf(asyncAction, meta)
: isResponseOf(asyncAction, meta)), (0, operators_1.filter)((action) => confirmed === undefined ||
!asyncAction.success.is(action) ||
'confirmed' in action.payload), (0, operators_1.take)(1), (0, operators_1.map)((action) => {
if (asyncAction.failure.is(action))
throw action.payload;
else if (action.payload?.confirmed === false)
throw new error_1.RaidenError(error_1.ErrorCodes.RDN_TRANSACTION_REORG, {
transactionHash: action.payload.txHash,
});
return action.payload;
})), { defaultValue: undefined });
}
exports.asyncActionToPromise = asyncActionToPromise;
// createReducer
/**
* Create a reducer which can be extended with additional actions handlers
*
* Usage:
* const reducer = createReducer(State)
* .handle(action, (s, a): State => ...)
* .handle(...)
* .handle(...);
*
* @param initialState - state for initialization (if no state is passed on reducer call)
* @returns A reducer function, extended with a handle method to extend it
*/
function createReducer(initialState) {
/**
* Make a reducer function for given handlers
*
* @param handlers - handlers to put into the reducer
* @returns reducer function for given handlers
*/
function makeReducer(handlers) {
const reducer = (state = initialState, action) => {
const handler = handlers[action.type];
if (handler && handler[0].is(action))
return handler[1](state, action); // calls registered handler
return state; // fallback returns unchanged state
};
/**
* Circular dependency on generic params forbids an already handled action from being accepted
*
* @param ac - Single or array of ActionCreators
* @param handler - handler to use
* @returns reducer with the action created incorporated
*/
function handle(ac, handler) {
const arr = Array.isArray(ac) ? ac : [ac];
(0, utils_1.assert)(!arr.some((a) => a.type in handlers), 'Already handled');
return makeReducer(Object.assign({}, handlers, ...arr.map((ac) => ({ [ac.type]: [ac, handler] }))));
}
// grow reducer function with our `handle` extender
return Object.assign(reducer, { handle });
}
// initially makes a reducer which doesn't handle anything (just returns unchanged state)
return makeReducer({});
}
exports.createReducer = createReducer;
//# sourceMappingURL=actions.js.map