UNPKG

raiden-ts

Version:

Raiden Light Client Typescript/Javascript SDK

242 lines 10.4 kB
"use strict"; 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