@tuwaio/pulsar-react 0.4.9 → 0.6.0

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 CHANGED
@@ -1,156 +1,63 @@
1
- # Pulsar React
1
+ # @tuwaio/pulsar-react
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@tuwaio/pulsar-react.svg)](https://www.npmjs.com/package/@tuwaio/pulsar-react)
4
- [![License](https://img.shields.io/npm/l/@tuwaio/pulsar-react.svg)](./LICENSE)
5
- [![Build Status](https://img.shields.io/github/actions/workflow/status/TuwaIO/pulsar-core/release.yml?branch=main)](https://github.com/TuwaIO/pulsar-core/actions)
4
+ [![License](https://img.shields.io/npm/l/@tuwaio/pulsar-react.svg)](https://github.com/TuwaIO/pulsar-core/blob/main/packages/pulsar-react/LICENSE)
6
5
 
7
- Layer 4 (L4) of the TUWA Ecosystem. Global React context bindings, hooks, and transaction pool initializers for orchestrating framework-agnostic Pulsar stores.
6
+ `@tuwaio/pulsar-react` is the React Layer 4 (L4) package of **Pulsar**, the transaction tracking project of TUWA Stage 2 ("State & Connection", next to Satellite Connect). Built on **`react`** only, it ships one hook, `useInitializeTransactionsPool`, that restarts the trackers of pending transactions when your app mounts. It has no UI components and no dependency on the other Pulsar packages: to read the store in components, use `createBoundedUseStore` from [`@tuwaio/pulsar-core`](https://pulsar.docs.tuwa.io/packages/pulsar-core).
8
7
 
9
8
  ---
10
9
 
11
- ## 🏛️ What is `@tuwaio/pulsar-react`?
10
+ ## 🏛️ Core Capabilities
12
11
 
13
- This package serves as the integration layer between the framework-agnostic `@tuwaio/pulsar-core` headless state machine and React. It provides global bindings, hooks, and transaction pool initializers to orchestrate Pulsar stores within the React component lifecycle.
14
-
15
- Its primary role is to execute `useInitializeTransactionsPool` to resume pending transaction tracking automatically across client-side refreshes.
12
+ - **Resume after reload:** `useInitializeTransactionsPool` calls the store's `initializeTransactionsPool` in an effect, on the client and after the store has restored its pool from `localStorage`, so transactions that were pending before a reload are tracked again.
13
+ - **Runs once:** the effect depends only on `initializeTransactionsPool`, and the latest `onError` is read without re-running it, so an inline `onError` does not start new trackers on every render.
14
+ - **Errors:** a rejected initialization goes to `onError`, or to `console.error` by default; nothing is reported after unmount.
16
15
 
17
16
  ---
18
17
 
19
18
  ## 💾 Installation
20
19
 
21
- To use this package, you need the complete Pulsar stack, including `@wagmi/core` for EVM interactions.
22
-
23
20
  ```bash
24
- # Using pnpm (recommended), but you can use npm, yarn or bun as well
25
21
  pnpm add @tuwaio/pulsar-react react
26
22
  ```
27
23
 
28
- ---
29
-
30
- ## 🚀 Getting Started
31
-
32
- The recommended way to integrate Pulsar with React is to create a vanilla store instance, create a bounded hook for it, and then use `useInitializeTransactionsPool` in your main layout component.
33
-
34
- Here is a complete step-by-step example:
35
-
36
- ### Step 1: Create the Pulsar Store and Hook
37
-
38
- First, create your vanilla Pulsar store and a reusable, bounded hook to access it. This pattern is recommended by Zustand for type safety and ease of use.
39
-
40
- ```ts
41
- // src/hooks/txTrackingHooks.ts
42
- import { createBoundedUseStore, createPulsarStore, Transaction } from '@tuwaio/pulsar-core';
43
- import { pulsarEvmAdapter } from '@tuwaio/pulsar-evm';
44
-
45
- import { appChains, config } from '@/configs/wagmiConfig';
46
-
47
- const storageName = 'transactions-tracking-storage';
48
-
49
- export enum TxType {
50
- example = 'example',
51
- }
52
-
53
- type ExampleTx = Transaction & {
54
- type: TxType.example;
55
- payload: {
56
- value: number;
57
- };
58
- };
59
-
60
- export type TransactionUnion = ExampleTx;
61
-
62
- export const usePulsarStore = createBoundedUseStore(
63
- createPulsarStore<TransactionUnion>({
64
- name: storageName,
65
- adapter: pulsarEvmAdapter(config, appChains),
66
- beforeTxProcess: async () => {
67
- // Optional global preflight. Throw here to block before wallet interaction.
68
- await assertUserCanSubmitTransactions();
69
- },
70
- }),
71
- );
72
- ```
24
+ > [!IMPORTANT]
25
+ > `react` (>=19.2.3) is a peer dependency and must be installed alongside `@tuwaio/pulsar-react`. The hook is used with a store from [`@tuwaio/pulsar-core`](https://pulsar.docs.tuwa.io/packages/pulsar-core).
73
26
 
74
- The preflight and metadata validation lives in `@tuwaio/pulsar-core`, not in React. Before wallet interaction or persistence, Pulsar validates that each `title` string is 100 characters or less, each `description` string is 300 characters or less, and the serialized `payload` is 10KB or less. Invalid pending transactions restored by `useInitializeTransactionsPool` are removed from persisted storage during initialization.
27
+ ---
75
28
 
76
- ### Step 2: Initialize the Store in Your App
29
+ ## 🚀 Usage
77
30
 
78
- Create a small, client-side component that uses the `useInitializeTransactionsPool` hook. This component's job is to re-activate trackers for pending transactions when the app loads.
31
+ Render the initializer once, in a component that stays mounted, such as your root providers:
79
32
 
80
33
  ```tsx
81
- // src/components/PulsarInitializer.tsx
82
34
  'use client';
83
35
 
36
+ import { createPulsarStore, type Transaction, type TxAdapter } from '@tuwaio/pulsar-core';
84
37
  import { useInitializeTransactionsPool } from '@tuwaio/pulsar-react';
85
- import { usePulsarStore } from '../hooks/txTrackingHooks';
86
-
87
- export const PulsarInitializer = () => {
88
- // Get the initialization function from the store via our custom hook
89
- const initializeTransactionsPool = usePulsarStore((state) => state.initializeTransactionsPool);
90
38
 
91
- // Pass the function to the hook from this package
92
- useInitializeTransactionsPool({ initializeTransactionsPool });
93
-
94
- return null; // This component renders nothing to the DOM
95
- };
96
- ```
39
+ declare const adapter: TxAdapter<Transaction>; // pulsarEvmAdapter(...) or pulsarSolanaAdapter(...)
97
40
 
98
- ### Step 3: Add the Initializer to Your Root Layout
41
+ export const pulsarStore = createPulsarStore<Transaction>({ name: 'pulsar-transactions', adapter });
99
42
 
100
- Finally, place the `PulsarInitializer` component at a high level in your application tree (e.g., in your root layout or providers component) so it runs on every page load.
43
+ export function PulsarInitializer() {
44
+ useInitializeTransactionsPool({
45
+ initializeTransactionsPool: pulsarStore.getState().initializeTransactionsPool,
46
+ onError: (error) => console.warn('Could not resume transaction tracking:', error),
47
+ });
101
48
 
102
- ```tsx
103
- // src/app/layout.tsx (Next.js example)
104
- import { WagmiProvider } from 'wagmi';
105
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
106
- import { wagmiConfig } from '../configs/wagmi';
107
- import { PulsarInitializer } from '../components/PulsarInitializer';
108
-
109
- const queryClient = new QueryClient();
110
-
111
- export default function RootLayout({ children }) {
112
- return (
113
- <html lang="en">
114
- <body>
115
- <WagmiProvider config={wagmiConfig}>
116
- <QueryClientProvider client={queryClient}>
117
- <PulsarInitializer />
118
- {children}
119
- </QueryClientProvider>
120
- </WagmiProvider>
121
- </body>
122
- </html>
123
- );
49
+ return null;
124
50
  }
125
51
  ```
126
52
 
127
- With this setup, your application is now fully configured to track transactions and resume tracking across page reloads.
53
+ Every call of `initializeTransactionsPool` starts new trackers, so do not render the initializer more than once. In development, React Strict Mode runs effects twice. The complete setup is on the **[Getting Started](https://pulsar.docs.tuwa.io/gettingStarted)** page.
128
54
 
129
55
  ---
130
56
 
131
- ## 📖 API Reference
132
-
133
- ### `useInitializeTransactionsPool(params)`
134
-
135
- This is the primary hook exported by this package. Its sole purpose is to re-initialize the transaction store on component mount.
136
-
137
- #### **Parameters**
138
-
139
- The hook accepts a single object with the following properties:
140
-
141
- - `initializeTransactionsPool: () => Promise<void>`: **(Required)** The initialization function obtained from your Pulsar store.
142
- - `onError?: (error: Error) => void`: **(Optional)** A callback function to handle any errors that occur during initialization. If not provided, errors will be logged to the console.
143
-
144
- ---
145
-
146
- ## 🤝 Contributing & Support
147
-
148
- Contributions are welcome! Please read our main **[Contribution Guidelines](https://github.com/TuwaIO/workflows/blob/main/CONTRIBUTING.md)**.
149
-
150
- If you find this library useful, please consider supporting its development. Every contribution helps!
57
+ ## 📚 API Reference
151
58
 
152
- [**➡️ View Support Options**](https://github.com/TuwaIO/workflows/blob/main/Donation.md)
59
+ Every export, with signatures and types generated from the source, is documented at **[pulsar.docs.tuwa.io/packages/pulsar-react](https://pulsar.docs.tuwa.io/packages/pulsar-react)**.
153
60
 
154
61
  ## 📄 License
155
62
 
156
- This project is licensed under the **Apache-2.0 License** - see the [LICENSE](./LICENSE) file for details.
63
+ Licensed under the **Apache-2.0 License**. See the [LICENSE](https://github.com/TuwaIO/pulsar-core/blob/main/packages/pulsar-react/LICENSE) file for details.
package/dist/index.d.mts CHANGED
@@ -1,45 +1,51 @@
1
1
  /**
2
- * @file React hook for bootstrapping the Pulsar transaction lifecycle on app start.
3
- * It rehydrates pending transaction trackers and can optionally perform an initial
4
- * remote history fetch right after tracker initialization.
2
+ * @file React hook that restarts the trackers of pending Pulsar transactions when the app mounts.
5
3
  */
6
4
  /**
7
- * Configuration for {@link useInitializeTransactionsPool}.
5
+ * The parameters of {@link useInitializeTransactionsPool}.
8
6
  */
9
7
  type UseInitializeTransactionsPoolParams = {
10
8
  /**
11
- * Re-initializes background trackers for all pending transactions stored in the Pulsar store.
9
+ * The store's `initializeTransactionsPool` action (`createPulsarStore` from `@tuwaio/pulsar-core`). Pass a stable
10
+ * reference: the hook runs it again whenever it changes.
12
11
  */
13
12
  initializeTransactionsPool: () => Promise<void>;
14
13
  /**
15
- * Optional error handler called when initialization or the optional initial fetch fails.
14
+ * Called when `initializeTransactionsPool` rejects. The latest function is used, so an inline callback does not run
15
+ * the initialization again.
16
16
  *
17
- * @defaultValue `console.error`
17
+ * @defaultValue Logs the error with `console.error`.
18
+ * @param error - The rejection reason of `initializeTransactionsPool`.
18
19
  */
19
20
  onError?: (error: Error) => void;
20
21
  };
21
22
  /**
22
- * Re-initializes pending transaction trackers when the component mounts.
23
+ * Calls `initializeTransactionsPool` in an effect after the component mounts, so the trackers of transactions that
24
+ * were pending before a page reload start again. It runs on the client only, after the store has restored its state
25
+ * from `localStorage`.
23
26
  *
24
- * Use this hook once in your application's root layout or top-level provider.
25
- * It restores tracker activity after reloads and can optionally fetch the initial
26
- * remote transaction history right after restoration.
27
+ * Use it once, in a component that stays mounted (a root layout or provider): every run starts new trackers. The
28
+ * effect runs again only when `initializeTransactionsPool` changes. In development, React Strict Mode runs effects
29
+ * twice, so pending transactions get two trackers there.
27
30
  *
28
- * @param params Hook configuration.
29
- * @param params.initializeTransactionsPool Function that restores trackers for pending transactions.
30
- * @param params.onError Optional custom error handler.
31
+ * @param params - The hook parameters.
32
+ * @param params.initializeTransactionsPool - The store's `initializeTransactionsPool` action.
33
+ * @param params.onError - Called when the initialization rejects; defaults to `console.error`. Not called after
34
+ * unmount.
31
35
  *
32
36
  * @example
33
37
  * ```tsx
34
38
  * import { useInitializeTransactionsPool } from '@tuwaio/pulsar-react';
35
39
  *
36
- * function AppLayout() {
40
+ * import { pulsarStore } from './pulsarStore';
41
+ *
42
+ * export function PulsarInitializer() {
37
43
  * useInitializeTransactionsPool({
38
- * initializeTransactionsPool: store.getState().initializeTransactionsPool,
44
+ * initializeTransactionsPool: pulsarStore.getState().initializeTransactionsPool,
39
45
  * onError: (error) => console.warn('Failed to restore transactions:', error),
40
46
  * });
41
47
  *
42
- * return <div>...</div>;
48
+ * return null;
43
49
  * }
44
50
  * ```
45
51
  */
package/dist/index.d.ts CHANGED
@@ -1,45 +1,51 @@
1
1
  /**
2
- * @file React hook for bootstrapping the Pulsar transaction lifecycle on app start.
3
- * It rehydrates pending transaction trackers and can optionally perform an initial
4
- * remote history fetch right after tracker initialization.
2
+ * @file React hook that restarts the trackers of pending Pulsar transactions when the app mounts.
5
3
  */
6
4
  /**
7
- * Configuration for {@link useInitializeTransactionsPool}.
5
+ * The parameters of {@link useInitializeTransactionsPool}.
8
6
  */
9
7
  type UseInitializeTransactionsPoolParams = {
10
8
  /**
11
- * Re-initializes background trackers for all pending transactions stored in the Pulsar store.
9
+ * The store's `initializeTransactionsPool` action (`createPulsarStore` from `@tuwaio/pulsar-core`). Pass a stable
10
+ * reference: the hook runs it again whenever it changes.
12
11
  */
13
12
  initializeTransactionsPool: () => Promise<void>;
14
13
  /**
15
- * Optional error handler called when initialization or the optional initial fetch fails.
14
+ * Called when `initializeTransactionsPool` rejects. The latest function is used, so an inline callback does not run
15
+ * the initialization again.
16
16
  *
17
- * @defaultValue `console.error`
17
+ * @defaultValue Logs the error with `console.error`.
18
+ * @param error - The rejection reason of `initializeTransactionsPool`.
18
19
  */
19
20
  onError?: (error: Error) => void;
20
21
  };
21
22
  /**
22
- * Re-initializes pending transaction trackers when the component mounts.
23
+ * Calls `initializeTransactionsPool` in an effect after the component mounts, so the trackers of transactions that
24
+ * were pending before a page reload start again. It runs on the client only, after the store has restored its state
25
+ * from `localStorage`.
23
26
  *
24
- * Use this hook once in your application's root layout or top-level provider.
25
- * It restores tracker activity after reloads and can optionally fetch the initial
26
- * remote transaction history right after restoration.
27
+ * Use it once, in a component that stays mounted (a root layout or provider): every run starts new trackers. The
28
+ * effect runs again only when `initializeTransactionsPool` changes. In development, React Strict Mode runs effects
29
+ * twice, so pending transactions get two trackers there.
27
30
  *
28
- * @param params Hook configuration.
29
- * @param params.initializeTransactionsPool Function that restores trackers for pending transactions.
30
- * @param params.onError Optional custom error handler.
31
+ * @param params - The hook parameters.
32
+ * @param params.initializeTransactionsPool - The store's `initializeTransactionsPool` action.
33
+ * @param params.onError - Called when the initialization rejects; defaults to `console.error`. Not called after
34
+ * unmount.
31
35
  *
32
36
  * @example
33
37
  * ```tsx
34
38
  * import { useInitializeTransactionsPool } from '@tuwaio/pulsar-react';
35
39
  *
36
- * function AppLayout() {
40
+ * import { pulsarStore } from './pulsarStore';
41
+ *
42
+ * export function PulsarInitializer() {
37
43
  * useInitializeTransactionsPool({
38
- * initializeTransactionsPool: store.getState().initializeTransactionsPool,
44
+ * initializeTransactionsPool: pulsarStore.getState().initializeTransactionsPool,
39
45
  * onError: (error) => console.warn('Failed to restore transactions:', error),
40
46
  * });
41
47
  *
42
- * return <div>...</div>;
48
+ * return null;
43
49
  * }
44
50
  * ```
45
51
  */
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var react=require('react');var c=({initializeTransactionsPool:r,onError:o})=>{react.useEffect(()=>{let i=true;return (async()=>{try{if(await r(),!i)return}catch(a){(o??(t=>{console.error("[Pulsar] Failed to initialize transactions pool:",t);}))(a);}})(),()=>{i=false;}},[r,o]);};exports.useInitializeTransactionsPool=c;
1
+ 'use strict';var react=require('react');var c=({initializeTransactionsPool:a,onError:i})=>{let t=react.useEffectEvent(r=>{(i??(o=>{console.error("[Pulsar] Failed to initialize transactions pool:",o);}))(r);});react.useEffect(()=>{let r=true;return (async()=>{try{await a();}catch(o){if(!r)return;t(o);}})(),()=>{r=false;}},[a]);};exports.useInitializeTransactionsPool=c;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {useEffect}from'react';var c=({initializeTransactionsPool:r,onError:o})=>{useEffect(()=>{let i=true;return (async()=>{try{if(await r(),!i)return}catch(a){(o??(t=>{console.error("[Pulsar] Failed to initialize transactions pool:",t);}))(a);}})(),()=>{i=false;}},[r,o]);};export{c as useInitializeTransactionsPool};
1
+ import {useEffectEvent,useEffect}from'react';var c=({initializeTransactionsPool:a,onError:i})=>{let t=useEffectEvent(r=>{(i??(o=>{console.error("[Pulsar] Failed to initialize transactions pool:",o);}))(r);});useEffect(()=>{let r=true;return (async()=>{try{await a();}catch(o){if(!r)return;t(o);}})(),()=>{r=false;}},[a]);};export{c as useInitializeTransactionsPool};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tuwaio/pulsar-react",
3
- "version": "0.4.9",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
7
- "description": "Layer 4 (L4) of the TUWA Ecosystem. Global React context bindings, hooks, and transaction pool initializers for orchestrating framework-agnostic Pulsar stores.",
7
+ "description": "L4 React package of Pulsar (TUWA): useInitializeTransactionsPool hook that resumes tracking of pending transactions after a page reload.",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
10
10
  "types": "./dist/index.d.ts",
@@ -16,12 +16,13 @@
16
16
  "socket.json"
17
17
  ],
18
18
  "keywords": [
19
+ "tuwa",
20
+ "pulsar",
21
+ "transaction-tracking",
22
+ "web3",
19
23
  "react",
20
24
  "hooks",
21
- "web3",
22
- "transaction",
23
- "tracking",
24
- "pulsar"
25
+ "typescript"
25
26
  ],
26
27
  "repository": {
27
28
  "type": "git",
@@ -42,13 +43,14 @@
42
43
  "react": ">=19.2.3"
43
44
  },
44
45
  "devDependencies": {
45
- "@types/react": "^19.2.18",
46
- "react": "^19.2.8",
46
+ "@types/react": "^19.3.0",
47
+ "react": "^19.3.0",
47
48
  "tsup": "^8.5.1",
48
- "typescript": "^6.0.3"
49
+ "typescript": "6.0.3"
49
50
  },
50
51
  "scripts": {
51
52
  "start": "tsup src/index.ts --watch",
52
- "build": "tsup"
53
+ "build": "tsup",
54
+ "test": "vitest run"
53
55
  }
54
56
  }