@tuwaio/pulsar-core 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -3
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -135,6 +135,40 @@ await store.getState().executeTxAction({
|
|
|
135
135
|
|
|
136
136
|
When a local callback is provided to `executeTxAction`, it replaces the global callback for that action.
|
|
137
137
|
|
|
138
|
+
### `abortOnTxError`
|
|
139
|
+
|
|
140
|
+
Use the `abortOnTxError` parameter (defaults to `true`) to control error propagation during transaction preflight and remote synchronization:
|
|
141
|
+
|
|
142
|
+
- **Preflight hook (`beforeTxProcess`)**:
|
|
143
|
+
- When `abortOnTxError` is `true` (default), any error thrown in `beforeTxProcess` will populate the `initialTx.error` state and throw, aborting the transaction action immediately.
|
|
144
|
+
- When `abortOnTxError` is `false`, any error thrown in `beforeTxProcess` is caught, logged to the console as a warning, and the transaction execution continues.
|
|
145
|
+
- **Remote sync hook (`onRemoteCreate`)**:
|
|
146
|
+
- Errors in `onRemoteCreate` **always** abort the transaction flow (the transaction is not added to the local tracking pool, `initialTx.error` is populated, and the error is thrown) regardless of the `abortOnTxError` setting.
|
|
147
|
+
|
|
148
|
+
You can set `abortOnTxError` globally during store creation or override it locally in `executeTxAction`:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
// Set globally (defaults to true if not provided)
|
|
152
|
+
const store = createPulsarStore<TransactionUnion>({
|
|
153
|
+
name: storageName,
|
|
154
|
+
adapter: pulsarEvmAdapter(config, appChains),
|
|
155
|
+
abortOnTxError: false, // Disable aborting for beforeTxProcess errors globally
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Override locally for a specific action
|
|
159
|
+
await store.getState().executeTxAction({
|
|
160
|
+
actionFunction: sendSwap,
|
|
161
|
+
abortOnTxError: true, // Force abort on beforeTxProcess errors for this action
|
|
162
|
+
params: {
|
|
163
|
+
adapter: OrbitAdapter.EVM,
|
|
164
|
+
desiredChainID: 1,
|
|
165
|
+
type: 'SWAP',
|
|
166
|
+
title: 'Swap',
|
|
167
|
+
description: 'Swap tokens',
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
138
172
|
### The Returned Store API
|
|
139
173
|
|
|
140
174
|
The `createPulsarStore` function returns a vanilla Zustand store with the following state and actions:
|
|
@@ -248,9 +282,7 @@ export type TransactionUnion = ExampleTx;
|
|
|
248
282
|
|
|
249
283
|
const initialStore = createPulsarStore<TransactionUnion>({
|
|
250
284
|
name: storageName,
|
|
251
|
-
adapter: [
|
|
252
|
-
pulsarEvmAdapter(config, appChains),
|
|
253
|
-
],
|
|
285
|
+
adapter: [pulsarEvmAdapter(config, appChains)],
|
|
254
286
|
onRemoteCreate: async (tx) => {
|
|
255
287
|
await syncTransaction(tx);
|
|
256
288
|
},
|
package/dist/index.d.mts
CHANGED
|
@@ -230,6 +230,8 @@ type PulsarAdapter<T extends Transaction> = OrbitGenericAdapter<TxAdapter<T>> &
|
|
|
230
230
|
beforeTxProcess?: BeforeTxProcess;
|
|
231
231
|
maxTransactions?: number;
|
|
232
232
|
gelatoApiKey?: string;
|
|
233
|
+
/** Optional setting to abort the transaction if the beforeTxProcess hook or remote creation fails. Defaults to true. */
|
|
234
|
+
abortOnTxError?: boolean;
|
|
233
235
|
} & SyncCallbacks<T>;
|
|
234
236
|
/**
|
|
235
237
|
* Represents a tracker for a specific transaction tied to an action and a connector.
|
|
@@ -343,7 +345,7 @@ interface IInitializeTxTrackingStore<T extends Transaction> {
|
|
|
343
345
|
* Adds a new transaction to the tracking pool and marks it as pending.
|
|
344
346
|
* @param tx The transaction object to add.
|
|
345
347
|
*/
|
|
346
|
-
addTxToPool: (tx: T) => void
|
|
348
|
+
addTxToPool: (tx: T) => Promise<void>;
|
|
347
349
|
/**
|
|
348
350
|
* Updates one or more properties of an existing transaction in the pool.
|
|
349
351
|
* @param txKey The key of the transaction to update.
|
|
@@ -391,6 +393,7 @@ type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {
|
|
|
391
393
|
params: Omit<InitialTransactionParams, 'actionFunction'>;
|
|
392
394
|
defaultTracker?: TransactionTracker;
|
|
393
395
|
beforeTxProcess?: BeforeTxProcess;
|
|
396
|
+
abortOnTxError?: boolean;
|
|
394
397
|
} & TrackerCallbacks<T>) => Promise<void>;
|
|
395
398
|
/**
|
|
396
399
|
* Initializes trackers for all pending transactions in the pool.
|
|
@@ -561,7 +564,7 @@ declare function createTxInMemoryStore<T extends Transaction>({ localTransaction
|
|
|
561
564
|
* @param options Configuration for the Zustand `persist` middleware.
|
|
562
565
|
* @returns A fully configured Zustand store instance.
|
|
563
566
|
*/
|
|
564
|
-
declare function createPulsarStore<T extends Transaction>({ adapter, maxTransactions, onRemoteCreate, gelatoApiKey, beforeTxProcess, ...options }: PulsarAdapter<T> & PersistOptions<ITxTrackingStore<T>>): Omit<zustand.StoreApi<ITxTrackingStore<T>>, "setState" | "persist"> & {
|
|
567
|
+
declare function createPulsarStore<T extends Transaction>({ adapter, maxTransactions, onRemoteCreate, gelatoApiKey, beforeTxProcess, abortOnTxError, ...options }: PulsarAdapter<T> & PersistOptions<ITxTrackingStore<T>>): Omit<zustand.StoreApi<ITxTrackingStore<T>>, "setState" | "persist"> & {
|
|
565
568
|
setState(partial: ITxTrackingStore<T> | Partial<ITxTrackingStore<T>> | ((state: ITxTrackingStore<T>) => ITxTrackingStore<T> | Partial<ITxTrackingStore<T>>), replace?: false | undefined): unknown;
|
|
566
569
|
setState(state: ITxTrackingStore<T> | ((state: ITxTrackingStore<T>) => ITxTrackingStore<T>), replace: true): unknown;
|
|
567
570
|
persist: {
|
package/dist/index.d.ts
CHANGED
|
@@ -230,6 +230,8 @@ type PulsarAdapter<T extends Transaction> = OrbitGenericAdapter<TxAdapter<T>> &
|
|
|
230
230
|
beforeTxProcess?: BeforeTxProcess;
|
|
231
231
|
maxTransactions?: number;
|
|
232
232
|
gelatoApiKey?: string;
|
|
233
|
+
/** Optional setting to abort the transaction if the beforeTxProcess hook or remote creation fails. Defaults to true. */
|
|
234
|
+
abortOnTxError?: boolean;
|
|
233
235
|
} & SyncCallbacks<T>;
|
|
234
236
|
/**
|
|
235
237
|
* Represents a tracker for a specific transaction tied to an action and a connector.
|
|
@@ -343,7 +345,7 @@ interface IInitializeTxTrackingStore<T extends Transaction> {
|
|
|
343
345
|
* Adds a new transaction to the tracking pool and marks it as pending.
|
|
344
346
|
* @param tx The transaction object to add.
|
|
345
347
|
*/
|
|
346
|
-
addTxToPool: (tx: T) => void
|
|
348
|
+
addTxToPool: (tx: T) => Promise<void>;
|
|
347
349
|
/**
|
|
348
350
|
* Updates one or more properties of an existing transaction in the pool.
|
|
349
351
|
* @param txKey The key of the transaction to update.
|
|
@@ -391,6 +393,7 @@ type ITxTrackingStore<T extends Transaction> = IInitializeTxTrackingStore<T> & {
|
|
|
391
393
|
params: Omit<InitialTransactionParams, 'actionFunction'>;
|
|
392
394
|
defaultTracker?: TransactionTracker;
|
|
393
395
|
beforeTxProcess?: BeforeTxProcess;
|
|
396
|
+
abortOnTxError?: boolean;
|
|
394
397
|
} & TrackerCallbacks<T>) => Promise<void>;
|
|
395
398
|
/**
|
|
396
399
|
* Initializes trackers for all pending transactions in the pool.
|
|
@@ -561,7 +564,7 @@ declare function createTxInMemoryStore<T extends Transaction>({ localTransaction
|
|
|
561
564
|
* @param options Configuration for the Zustand `persist` middleware.
|
|
562
565
|
* @returns A fully configured Zustand store instance.
|
|
563
566
|
*/
|
|
564
|
-
declare function createPulsarStore<T extends Transaction>({ adapter, maxTransactions, onRemoteCreate, gelatoApiKey, beforeTxProcess, ...options }: PulsarAdapter<T> & PersistOptions<ITxTrackingStore<T>>): Omit<zustand.StoreApi<ITxTrackingStore<T>>, "setState" | "persist"> & {
|
|
567
|
+
declare function createPulsarStore<T extends Transaction>({ adapter, maxTransactions, onRemoteCreate, gelatoApiKey, beforeTxProcess, abortOnTxError, ...options }: PulsarAdapter<T> & PersistOptions<ITxTrackingStore<T>>): Omit<zustand.StoreApi<ITxTrackingStore<T>>, "setState" | "persist"> & {
|
|
565
568
|
setState(partial: ITxTrackingStore<T> | Partial<ITxTrackingStore<T>> | ((state: ITxTrackingStore<T>) => ITxTrackingStore<T> | Partial<ITxTrackingStore<T>>), replace?: false | undefined): unknown;
|
|
566
569
|
setState(state: ITxTrackingStore<T> | ((state: ITxTrackingStore<T>) => ITxTrackingStore<T>), replace: true): unknown;
|
|
567
570
|
persist: {
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var immer=require('immer'),vanilla=require('zustand/vanilla'),orbitCore=require('@tuwaio/orbit-core'),
|
|
1
|
+
'use strict';var immer=require('immer'),vanilla=require('zustand/vanilla'),orbitCore=require('@tuwaio/orbit-core'),ie=require('dayjs'),middleware=require('zustand/middleware'),zustand=require('zustand');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ie__default=/*#__PURE__*/_interopDefault(ie);var N=100,B=300,z=10*1024,ee=[/\beval\s*\(/i,/\bFunction\s*\(/,/\bset(?:Timeout|Interval)\s*\(\s*['"`]/i,/javascript\s*:/i],P=class extends Error{field;constructor(e,r){super(r),this.name="PulsarTransactionValidationError",this.field=e;}};function $(t){I({field:"title",value:t.title,maxLength:N}),I({field:"description",value:t.description,maxLength:B}),_(t.payload);}function k(t){I({field:"title",value:t.title,maxLength:N}),I({field:"description",value:t.description,maxLength:B}),_(t.payload);}function I({field:t,value:e,maxLength:r}){if(e===void 0)return;(Array.isArray(e)?e:[e]).forEach((n,o)=>{let c=Array.isArray(e)?`${t}[${o}]`:t;if(typeof n!="string")throw new P(c,`${c} must be a string.`);if(n.length>r)throw new P(c,`${c} must be ${r} characters or less.`);R(c,n);});}function _(t){if(t===void 0)return;let e;try{e=JSON.stringify(t);}catch{throw new P("payload","payload must be JSON-serializable.")}if(e===void 0)throw new P("payload","payload must be JSON-serializable.");if(new TextEncoder().encode(e).length>z)throw new P("payload",`payload must be ${z} bytes or less when serialized.`);j(t);}function j(t,e="payload"){if(typeof t=="string"){R(e,t);return}t===null||typeof t!="object"||Object.entries(t).forEach(([r,l])=>{let n=`${e}.${r}`;R(n,r),j(l,n);});}function R(t,e){if(ee.some(r=>r.test(e)))throw new P(t,`${t} contains a blocked executable-like pattern.`)}function U({maxTransactions:t,onRemoteCreate:e}){return (r,l)=>({transactionsPool:{},lastAddedTxKey:void 0,initialTx:void 0,addTxToPool:n=>{k(n);let o={...n,pending:true};return (async()=>{e&&await e(o),r(s=>immer.produce(s,a=>{if(a.lastAddedTxKey=n.txKey,n.txKey){if(Object.keys(a.transactionsPool).length>=t){let d=Object.values(a.transactionsPool).sort((i,T)=>i.localTimestamp-T.localTimestamp);if(d.length>0){let i=d[0];delete a.transactionsPool[i.txKey];}}a.transactionsPool[n.txKey]=o;}}));})()},updateTxParams:(n,o)=>{r(c=>immer.produce(c,s=>{let a=s.transactionsPool[n];a&&Object.assign(a,o);}));},removeTxFromPool:n=>{r(o=>immer.produce(o,c=>{delete c.transactionsPool[n];}));},closeTxTrackedModal:n=>{r(o=>immer.produce(o,c=>{if(n&&c.transactionsPool[n]){let s=c.transactionsPool[n];c.transactionsPool[n]={...s,isTrackedModalOpen:false};}c.initialTx=void 0;}));},getLastTxKey:()=>l().lastAddedTxKey})}var G=t=>Object.values(t).sort((e,r)=>Number(e.localTimestamp)-Number(r.localTimestamp)),fe=t=>G(t).filter(e=>e.pending),ge=(t,e)=>t[e],te=(t,e)=>G(t).filter(r=>r.from.toLowerCase()===e.toLowerCase()),Pe=(t,e)=>te(t,e).filter(r=>r.pending);var re=(n=>(n.Ethereum="ethereum",n.Safe="safe",n.Gelato="gelato",n.Solana="solana",n))(re||{}),O=(l=>(l.Failed="Failed",l.Success="Success",l.Replaced="Replaced",l))(O||{});var q=t=>t==="Success"||t==="Replaced",X=(t,e)=>{let r=t[e.txKey];if(r){if(q(r.status))return false;if(r.pending){if(q(e.status))return t[e.txKey]={...r,...e},true;let l=typeof e.confirmations=="number"?e.confirmations:0,n=typeof r.confirmations=="number"?r.confirmations:0;return l>n?(t[e.txKey]={...r,...e},true):false}}return t[e.txKey]=e,true};function Ee({localTransactionsPool:t,getHistory:e,onHistoryFetched:r}){immer.setAutoFreeze(false);let l=o=>({isLoading:o,isError:false}),n=o=>o?(r&&queueMicrotask(()=>r(o.docs)),c=>immer.produce(c,s=>{let a=s.transactionsPool;for(let m of o.docs)X(a,m);s.currentPage=o.page,s.hasMore=o.hasNextPage,s.isLoading=false;})):c=>c;return vanilla.createStore()((o,c)=>({transactionsPool:t,isLoading:false,isError:false,hasMore:false,currentPage:1,syncWithLocalPool:s=>{o(a=>immer.produce(a,m=>{let d=m.transactionsPool;for(let i of Object.values(s))X(d,i);}));},fetchInitial:async s=>{if(!(!e||!s)){o(l(true));try{let a=await e({page:1,walletAddress:s});o(n(a));}catch(a){console.error("[Pulsar] Failed to fetch initial transaction history:",a),o({isLoading:false,isError:true});}}},fetchNextPage:async s=>{let{hasMore:a,isLoading:m,currentPage:d}=c();if(!(!e||!a||m||!s)){o(l(true));try{let i=d+1,T=await e({page:i,walletAddress:s});o(n(T));}catch(i){console.error(`[Pulsar] Failed to fetch transaction history page ${d+1}:`,i),o({isLoading:false,isError:true});}}}}))}function Ge({adapter:t,maxTransactions:e=50,onRemoteCreate:r,gelatoApiKey:l,beforeTxProcess:n,abortOnTxError:o,...c}){return vanilla.createStore()(middleware.persist((s,a)=>({...U({maxTransactions:e,onRemoteCreate:r})(s,a),getAdapter:()=>t,initializeTransactionsPool:async()=>{let d=Object.values(a().transactionsPool).filter(i=>i.pending).filter(i=>{try{return k(i),!0}catch(T){return console.warn("[Pulsar] Removed invalid persisted transaction:",T),a().removeTxFromPool(i.txKey),false}});await Promise.all(d.map(i=>orbitCore.selectAdapterByKey({adapterKey:i.adapter,adapter:t})?.checkAndInitializeTrackerInStore({tx:i,gelatoApiKey:l,...a()})));},injectExternalPendingTxs:async m=>{let i=a().getAdapter(),T=[],h=m.filter(f=>{try{return k(f),!0}catch(u){return console.warn("[Pulsar] Skipped invalid remote transaction:",u),false}});s(f=>immer.produce(f,u=>{let S=u.transactionsPool;h.forEach(p=>{let g=S[p.txKey];p.pending&&!g&&(S[p.txKey]=p,T.push(p));let A=p.status==="Success"||p.status==="Failed"||p.status==="Replaced";g?.pending&&A&&(g.status=p.status,g.pending=false,p.txKey&&(g.txKey=p.txKey),p.finishedTimestamp&&(g.finishedTimestamp=p.finishedTimestamp));});})),T.length>0&&await Promise.all(T.map(f=>orbitCore.selectAdapterByKey({adapterKey:f.adapter,adapter:i})?.checkAndInitializeTrackerInStore({tx:f,gelatoApiKey:l,...a()})));},executeTxAction:async({defaultTracker:m,actionFunction:d,params:i,beforeTxProcess:T,abortOnTxError:h,...f})=>{let u=h??o??true,S=ie__default.default().unix();try{await(T??n)?.();}catch(x){if(u)throw s({initialTx:{...i,actionFunction:d,localTimestamp:S,isInitializing:false,error:orbitCore.normalizeError(x)}}),x;console.warn("[Pulsar] beforeTxProcess failed:",x);}$(i);let{desiredChainID:p,tracker:g,...A}=i,{onSuccess:W,onError:J,onReplaced:V}=f;s({initialTx:{...i,actionFunction:d,localTimestamp:S,isInitializing:true}});let b=orbitCore.selectAdapterByKey({adapterKey:A.adapter,adapter:t}),L=x=>{s(w=>immer.produce(w,y=>{y.initialTx&&(y.initialTx.isInitializing=false,y.initialTx.error=orbitCore.normalizeError(x));}));};if(!b){let x=new Error("No adapter found for this transaction.");throw L(x),x}try{let{connectorType:x,walletAddress:w}=b.getConnectorInfo();await b.checkChainForTx(p);let y=await d();if(!y){s({initialTx:void 0});return}let{tracker:M,txKey:E}=b.checkTransactionsTracker({actionTxKey:y,connectorType:x,tracker:g,gelatoApiKey:l}),Y={...A,connectorType:x,from:w,tracker:M||m,chainId:orbitCore.setChainId(p),localTimestamp:S,txKey:E,hash:M==="ethereum"?y:void 0,pending:!1,isTrackedModalOpen:i.withTrackedModal};await a().addTxToPool(Y),s(Z=>immer.produce(Z,K=>{K.initialTx&&(K.initialTx.isInitializing=!1,K.initialTx.lastTxKey=E);}));let Q=a().transactionsPool[E];await b.checkAndInitializeTrackerInStore({tx:Q,onSuccess:W,onError:J,onReplaced:V,gelatoApiKey:l,...a()});}catch(x){throw L(x),x}}}),{...c}))}var He=(t=>e=>zustand.useStore(t,e));var Te=5e3,de=10;function Je(t){let{tx:e,fetcher:r,onInitialize:l,onSuccess:n,onFailure:o,onIntervalTick:c,onReplaced:s,removeTxFromPool:a,pollingInterval:m=Te,maxRetries:d=de}=t;if(!e.pending)return;l?.();let i=d,T=true,h=u=>{T&&(T=false,a&&!u?.withoutRemoving&&a(e.txKey));};(async()=>{for(;T&&i>0;)try{if(await new Promise(u=>setTimeout(u,m)),!T)break;await r({tx:e,stopPolling:h,onSuccess:n,onFailure:o,onIntervalTick:c,onReplaced:s});}catch(u){console.error(`Polling fetcher for txKey ${e.txKey} threw an error:`,u),i--;}i<=0&&(console.warn(`Polling for txKey ${e.txKey} stopped after reaching the maximum number of retries.`),o(),h());})();}exports.MAX_TRANSACTION_DESCRIPTION_LENGTH=B;exports.MAX_TRANSACTION_PAYLOAD_BYTES=z;exports.MAX_TRANSACTION_TITLE_LENGTH=N;exports.PulsarTransactionValidationError=P;exports.TransactionStatus=O;exports.TransactionTracker=re;exports.createBoundedUseStore=He;exports.createPulsarStore=Ge;exports.createTxInMemoryStore=Ee;exports.initializePollingTracker=Je;exports.initializeTxTrackingStore=U;exports.selectAllTransactions=G;exports.selectAllTransactionsByActiveWallet=te;exports.selectPendingTransactions=fe;exports.selectPendingTransactionsByActiveWallet=Pe;exports.selectTxByKey=ge;exports.validateInitialTransactionParams=$;exports.validateTransaction=k;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {produce,setAutoFreeze}from'immer';import {createStore}from'zustand/vanilla';import {selectAdapterByKey,setChainId
|
|
1
|
+
import {produce,setAutoFreeze}from'immer';import {createStore}from'zustand/vanilla';import {normalizeError,selectAdapterByKey,setChainId}from'@tuwaio/orbit-core';import ie from'dayjs';import {persist}from'zustand/middleware';import {useStore}from'zustand';var N=100,B=300,z=10*1024,ee=[/\beval\s*\(/i,/\bFunction\s*\(/,/\bset(?:Timeout|Interval)\s*\(\s*['"`]/i,/javascript\s*:/i],P=class extends Error{field;constructor(e,r){super(r),this.name="PulsarTransactionValidationError",this.field=e;}};function $(t){I({field:"title",value:t.title,maxLength:N}),I({field:"description",value:t.description,maxLength:B}),_(t.payload);}function k(t){I({field:"title",value:t.title,maxLength:N}),I({field:"description",value:t.description,maxLength:B}),_(t.payload);}function I({field:t,value:e,maxLength:r}){if(e===void 0)return;(Array.isArray(e)?e:[e]).forEach((n,o)=>{let c=Array.isArray(e)?`${t}[${o}]`:t;if(typeof n!="string")throw new P(c,`${c} must be a string.`);if(n.length>r)throw new P(c,`${c} must be ${r} characters or less.`);R(c,n);});}function _(t){if(t===void 0)return;let e;try{e=JSON.stringify(t);}catch{throw new P("payload","payload must be JSON-serializable.")}if(e===void 0)throw new P("payload","payload must be JSON-serializable.");if(new TextEncoder().encode(e).length>z)throw new P("payload",`payload must be ${z} bytes or less when serialized.`);j(t);}function j(t,e="payload"){if(typeof t=="string"){R(e,t);return}t===null||typeof t!="object"||Object.entries(t).forEach(([r,l])=>{let n=`${e}.${r}`;R(n,r),j(l,n);});}function R(t,e){if(ee.some(r=>r.test(e)))throw new P(t,`${t} contains a blocked executable-like pattern.`)}function U({maxTransactions:t,onRemoteCreate:e}){return (r,l)=>({transactionsPool:{},lastAddedTxKey:void 0,initialTx:void 0,addTxToPool:n=>{k(n);let o={...n,pending:true};return (async()=>{e&&await e(o),r(s=>produce(s,a=>{if(a.lastAddedTxKey=n.txKey,n.txKey){if(Object.keys(a.transactionsPool).length>=t){let d=Object.values(a.transactionsPool).sort((i,T)=>i.localTimestamp-T.localTimestamp);if(d.length>0){let i=d[0];delete a.transactionsPool[i.txKey];}}a.transactionsPool[n.txKey]=o;}}));})()},updateTxParams:(n,o)=>{r(c=>produce(c,s=>{let a=s.transactionsPool[n];a&&Object.assign(a,o);}));},removeTxFromPool:n=>{r(o=>produce(o,c=>{delete c.transactionsPool[n];}));},closeTxTrackedModal:n=>{r(o=>produce(o,c=>{if(n&&c.transactionsPool[n]){let s=c.transactionsPool[n];c.transactionsPool[n]={...s,isTrackedModalOpen:false};}c.initialTx=void 0;}));},getLastTxKey:()=>l().lastAddedTxKey})}var G=t=>Object.values(t).sort((e,r)=>Number(e.localTimestamp)-Number(r.localTimestamp)),fe=t=>G(t).filter(e=>e.pending),ge=(t,e)=>t[e],te=(t,e)=>G(t).filter(r=>r.from.toLowerCase()===e.toLowerCase()),Pe=(t,e)=>te(t,e).filter(r=>r.pending);var re=(n=>(n.Ethereum="ethereum",n.Safe="safe",n.Gelato="gelato",n.Solana="solana",n))(re||{}),O=(l=>(l.Failed="Failed",l.Success="Success",l.Replaced="Replaced",l))(O||{});var q=t=>t==="Success"||t==="Replaced",X=(t,e)=>{let r=t[e.txKey];if(r){if(q(r.status))return false;if(r.pending){if(q(e.status))return t[e.txKey]={...r,...e},true;let l=typeof e.confirmations=="number"?e.confirmations:0,n=typeof r.confirmations=="number"?r.confirmations:0;return l>n?(t[e.txKey]={...r,...e},true):false}}return t[e.txKey]=e,true};function Ee({localTransactionsPool:t,getHistory:e,onHistoryFetched:r}){setAutoFreeze(false);let l=o=>({isLoading:o,isError:false}),n=o=>o?(r&&queueMicrotask(()=>r(o.docs)),c=>produce(c,s=>{let a=s.transactionsPool;for(let m of o.docs)X(a,m);s.currentPage=o.page,s.hasMore=o.hasNextPage,s.isLoading=false;})):c=>c;return createStore()((o,c)=>({transactionsPool:t,isLoading:false,isError:false,hasMore:false,currentPage:1,syncWithLocalPool:s=>{o(a=>produce(a,m=>{let d=m.transactionsPool;for(let i of Object.values(s))X(d,i);}));},fetchInitial:async s=>{if(!(!e||!s)){o(l(true));try{let a=await e({page:1,walletAddress:s});o(n(a));}catch(a){console.error("[Pulsar] Failed to fetch initial transaction history:",a),o({isLoading:false,isError:true});}}},fetchNextPage:async s=>{let{hasMore:a,isLoading:m,currentPage:d}=c();if(!(!e||!a||m||!s)){o(l(true));try{let i=d+1,T=await e({page:i,walletAddress:s});o(n(T));}catch(i){console.error(`[Pulsar] Failed to fetch transaction history page ${d+1}:`,i),o({isLoading:false,isError:true});}}}}))}function Ge({adapter:t,maxTransactions:e=50,onRemoteCreate:r,gelatoApiKey:l,beforeTxProcess:n,abortOnTxError:o,...c}){return createStore()(persist((s,a)=>({...U({maxTransactions:e,onRemoteCreate:r})(s,a),getAdapter:()=>t,initializeTransactionsPool:async()=>{let d=Object.values(a().transactionsPool).filter(i=>i.pending).filter(i=>{try{return k(i),!0}catch(T){return console.warn("[Pulsar] Removed invalid persisted transaction:",T),a().removeTxFromPool(i.txKey),false}});await Promise.all(d.map(i=>selectAdapterByKey({adapterKey:i.adapter,adapter:t})?.checkAndInitializeTrackerInStore({tx:i,gelatoApiKey:l,...a()})));},injectExternalPendingTxs:async m=>{let i=a().getAdapter(),T=[],h=m.filter(f=>{try{return k(f),!0}catch(u){return console.warn("[Pulsar] Skipped invalid remote transaction:",u),false}});s(f=>produce(f,u=>{let S=u.transactionsPool;h.forEach(p=>{let g=S[p.txKey];p.pending&&!g&&(S[p.txKey]=p,T.push(p));let A=p.status==="Success"||p.status==="Failed"||p.status==="Replaced";g?.pending&&A&&(g.status=p.status,g.pending=false,p.txKey&&(g.txKey=p.txKey),p.finishedTimestamp&&(g.finishedTimestamp=p.finishedTimestamp));});})),T.length>0&&await Promise.all(T.map(f=>selectAdapterByKey({adapterKey:f.adapter,adapter:i})?.checkAndInitializeTrackerInStore({tx:f,gelatoApiKey:l,...a()})));},executeTxAction:async({defaultTracker:m,actionFunction:d,params:i,beforeTxProcess:T,abortOnTxError:h,...f})=>{let u=h??o??true,S=ie().unix();try{await(T??n)?.();}catch(x){if(u)throw s({initialTx:{...i,actionFunction:d,localTimestamp:S,isInitializing:false,error:normalizeError(x)}}),x;console.warn("[Pulsar] beforeTxProcess failed:",x);}$(i);let{desiredChainID:p,tracker:g,...A}=i,{onSuccess:W,onError:J,onReplaced:V}=f;s({initialTx:{...i,actionFunction:d,localTimestamp:S,isInitializing:true}});let b=selectAdapterByKey({adapterKey:A.adapter,adapter:t}),L=x=>{s(w=>produce(w,y=>{y.initialTx&&(y.initialTx.isInitializing=false,y.initialTx.error=normalizeError(x));}));};if(!b){let x=new Error("No adapter found for this transaction.");throw L(x),x}try{let{connectorType:x,walletAddress:w}=b.getConnectorInfo();await b.checkChainForTx(p);let y=await d();if(!y){s({initialTx:void 0});return}let{tracker:M,txKey:E}=b.checkTransactionsTracker({actionTxKey:y,connectorType:x,tracker:g,gelatoApiKey:l}),Y={...A,connectorType:x,from:w,tracker:M||m,chainId:setChainId(p),localTimestamp:S,txKey:E,hash:M==="ethereum"?y:void 0,pending:!1,isTrackedModalOpen:i.withTrackedModal};await a().addTxToPool(Y),s(Z=>produce(Z,K=>{K.initialTx&&(K.initialTx.isInitializing=!1,K.initialTx.lastTxKey=E);}));let Q=a().transactionsPool[E];await b.checkAndInitializeTrackerInStore({tx:Q,onSuccess:W,onError:J,onReplaced:V,gelatoApiKey:l,...a()});}catch(x){throw L(x),x}}}),{...c}))}var He=(t=>e=>useStore(t,e));var Te=5e3,de=10;function Je(t){let{tx:e,fetcher:r,onInitialize:l,onSuccess:n,onFailure:o,onIntervalTick:c,onReplaced:s,removeTxFromPool:a,pollingInterval:m=Te,maxRetries:d=de}=t;if(!e.pending)return;l?.();let i=d,T=true,h=u=>{T&&(T=false,a&&!u?.withoutRemoving&&a(e.txKey));};(async()=>{for(;T&&i>0;)try{if(await new Promise(u=>setTimeout(u,m)),!T)break;await r({tx:e,stopPolling:h,onSuccess:n,onFailure:o,onIntervalTick:c,onReplaced:s});}catch(u){console.error(`Polling fetcher for txKey ${e.txKey} threw an error:`,u),i--;}i<=0&&(console.warn(`Polling for txKey ${e.txKey} stopped after reaching the maximum number of retries.`),o(),h());})();}export{B as MAX_TRANSACTION_DESCRIPTION_LENGTH,z as MAX_TRANSACTION_PAYLOAD_BYTES,N as MAX_TRANSACTION_TITLE_LENGTH,P as PulsarTransactionValidationError,O as TransactionStatus,re as TransactionTracker,He as createBoundedUseStore,Ge as createPulsarStore,Ee as createTxInMemoryStore,Je as initializePollingTracker,U as initializeTxTrackingStore,G as selectAllTransactions,te as selectAllTransactionsByActiveWallet,fe as selectPendingTransactions,Pe as selectPendingTransactionsByActiveWallet,ge as selectTxByKey,$ as validateInitialTransactionParams,k as validateTransaction};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuwaio/pulsar-core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Oleksandr Tkach",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@tuwaio/orbit-core": "^0.2.8",
|
|
50
|
-
"dayjs": "^1.11.
|
|
50
|
+
"dayjs": "^1.11.21",
|
|
51
51
|
"immer": "^11.1.8",
|
|
52
52
|
"tsup": "^8.5.1",
|
|
53
53
|
"typescript": "^6.0.3",
|
|
54
|
-
"vitest": "^4.1.
|
|
54
|
+
"vitest": "^4.1.7",
|
|
55
55
|
"zustand": "^5.0.13"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|