@ecency/sdk 1.5.6 → 1.5.8

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
@@ -2,12 +2,212 @@
2
2
 
3
3
  Framework-agnostic data layer for Hive apps with first-class React Query support.
4
4
 
5
- ## Whats Inside
5
+ ## What's Inside
6
6
 
7
7
  - Query and mutation option builders powered by [@tanstack/react-query](https://tanstack.com/query)
8
8
  - Modular APIs: accounts, posts, communities, market, wallet, notifications, analytics, integrations, core, auth, bridge, games, hive-engine, operations, points, private-api, promotions, proposals, resource-credits, search, spk, witnesses
9
9
  - Central configuration via `CONFIG` / `ConfigManager` (RPC client, QueryClient)
10
10
 
11
+ ## Why React Query?
12
+
13
+ The Ecency SDK is built on **React Query** (TanStack Query) to provide a production-ready data synchronization layer out of the box. React Query transforms how Hive applications handle server state, eliminating common pitfalls and dramatically improving user experience.
14
+
15
+ ### Key Benefits
16
+
17
+ #### 1. **Automatic Caching & Deduplication**
18
+ Multiple components can request the same data without redundant network calls. React Query automatically:
19
+ - Caches responses by query key
20
+ - Deduplicates concurrent requests
21
+ - Shares cached data across components instantly
22
+
23
+ ```ts
24
+ // Both components use the same query - only 1 API call is made
25
+ // Component A
26
+ useQuery(getAccountFullQueryOptions("ecency"));
27
+
28
+ // Component B (rendered simultaneously)
29
+ useQuery(getAccountFullQueryOptions("ecency")); // ← Uses cached data
30
+ ```
31
+
32
+ #### 2. **Background Synchronization**
33
+ Data automatically stays fresh without manual refetching. React Query:
34
+ - Refetches stale data on window focus
35
+ - Updates data on network reconnection
36
+ - Supports configurable background polling
37
+ - Prevents showing outdated information
38
+
39
+ ```ts
40
+ // Data refetches automatically when user returns to tab
41
+ const { data } = useQuery({
42
+ ...getPostsRankedQueryOptions("trending", "", "", 20),
43
+ staleTime: 60000, // Consider fresh for 60s
44
+ refetchInterval: 120000 // Poll every 2 minutes
45
+ });
46
+ ```
47
+
48
+ #### 3. **Optimistic Updates**
49
+ Instant UI feedback before blockchain confirmation:
50
+
51
+ ```ts
52
+ const { mutateAsync } = useAccountUpdate(username, auth);
53
+
54
+ await mutateAsync(
55
+ { metadata: newProfile },
56
+ {
57
+ // Update UI immediately
58
+ onMutate: (variables) => {
59
+ queryClient.setQueryData(
60
+ getAccountFullQueryOptions(username).queryKey,
61
+ (old) => ({ ...old, ...variables.metadata })
62
+ );
63
+ },
64
+ // Rollback on error
65
+ onError: (err, variables, context) => {
66
+ queryClient.setQueryData(
67
+ getAccountFullQueryOptions(username).queryKey,
68
+ context.previousData
69
+ );
70
+ }
71
+ }
72
+ );
73
+ ```
74
+
75
+ #### 4. **SSR & Prefetching**
76
+ First-class server-side rendering support:
77
+
78
+ ```tsx
79
+ // Next.js App Router example
80
+ export async function generateMetadata({ params }) {
81
+ const queryClient = new QueryClient();
82
+
83
+ // Prefetch on server
84
+ await queryClient.prefetchQuery(
85
+ getAccountFullQueryOptions(params.username)
86
+ );
87
+
88
+ // Data is hydrated on client instantly
89
+ return { title: /* ... */ };
90
+ }
91
+ ```
92
+
93
+ #### 5. **Loading & Error States**
94
+ Built-in state management eliminates boilerplate:
95
+
96
+ ```ts
97
+ const { data, isLoading, error, isRefetching } = useQuery(
98
+ getAccountFullQueryOptions("ecency")
99
+ );
100
+
101
+ if (isLoading) return <Spinner />;
102
+ if (error) return <ErrorMessage error={error} />;
103
+
104
+ return <Profile data={data} isRefreshing={isRefetching} />;
105
+ ```
106
+
107
+ #### 6. **Dependent Queries**
108
+ Chain queries with automatic dependency tracking:
109
+
110
+ ```ts
111
+ // Step 1: Fetch account
112
+ const { data: account } = useQuery(getAccountFullQueryOptions(username));
113
+
114
+ // Step 2: Fetch wallet only after account loads
115
+ const { data: wallet } = useQuery({
116
+ ...getAccountWalletAssetInfoQueryOptions(username, "HIVE"),
117
+ enabled: !!account // Wait for account
118
+ });
119
+ ```
120
+
121
+ #### 7. **Pagination & Infinite Scroll**
122
+ Built-in pagination utilities:
123
+
124
+ ```ts
125
+ const {
126
+ data,
127
+ fetchNextPage,
128
+ hasNextPage,
129
+ isFetchingNextPage
130
+ } = useInfiniteQuery(
131
+ getPostsRankedInfiniteQueryOptions("trending", "hive-engine")
132
+ );
133
+
134
+ // Automatically manages page state and cursor tracking
135
+ ```
136
+
137
+ ### Why This Matters for Hive Apps
138
+
139
+ Hive applications face unique challenges:
140
+ - **High API latency**: Blockchain RPC calls can be slow (100-500ms)
141
+ - **Rate limits**: Excessive requests can hit node rate limits
142
+ - **Stale data**: Blockchain data changes frequently (new posts, votes, transfers)
143
+ - **Complex state**: Managing loading states, errors, and cache invalidation manually is error-prone
144
+
145
+ The Ecency SDK with React Query solves all of these:
146
+
147
+ ✅ **Reduced API calls** by 70-90% through intelligent caching
148
+ ✅ **Instant UI updates** with optimistic mutations
149
+ ✅ **Zero manual cache management** - React Query handles invalidation
150
+ ✅ **Better UX** with background updates and retry logic
151
+ ✅ **Faster perceived performance** with prefetching and SSR
152
+ ✅ **Less code** - no custom loading/error/caching logic needed
153
+
154
+ ### How Other Apps Can Benefit
155
+
156
+ Any Hive application can leverage this SDK to:
157
+
158
+ 1. **Drop custom data fetching code** - Use pre-built query options for all common Hive operations
159
+ 2. **Share cache across features** - One query for account data serves entire app
160
+ 3. **Add real-time features** easily with `refetchInterval` and optimistic updates
161
+ 4. **Improve SEO** with SSR-ready queries that prefetch on server
162
+ 5. **Reduce bundle size** - Share the SDK's type-safe queries instead of custom fetch logic
163
+
164
+ **Example: Building a Hive blog reader**
165
+
166
+ ```tsx
167
+ import { useQuery, useInfiniteQuery } from "@tanstack/react-query";
168
+ import {
169
+ getAccountFullQueryOptions,
170
+ getPostQueryOptions,
171
+ getPostsRankedInfiniteQueryOptions
172
+ } from "@ecency/sdk";
173
+
174
+ // Profile page - automatic caching
175
+ function ProfilePage({ username }) {
176
+ const { data: account, isLoading } = useQuery(
177
+ getAccountFullQueryOptions(username)
178
+ );
179
+ // ✅ Cached automatically, shared across components
180
+ // ✅ Refetches on window focus
181
+ // ✅ Handles loading/error states
182
+ }
183
+
184
+ // Feed page - infinite scroll
185
+ function FeedPage() {
186
+ const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(
187
+ getPostsRankedInfiniteQueryOptions("trending")
188
+ );
189
+ // ✅ Automatic pagination
190
+ // ✅ Background updates
191
+ // ✅ Deduplicates concurrent requests
192
+ }
193
+
194
+ // Post page - dependent queries
195
+ function PostPage({ author, permlink }) {
196
+ const { data: post } = useQuery(
197
+ getPostQueryOptions(author, permlink)
198
+ );
199
+
200
+ const { data: authorAccount } = useQuery({
201
+ ...getAccountFullQueryOptions(post?.author),
202
+ enabled: !!post // Wait for post to load
203
+ });
204
+ // ✅ Efficient dependent loading
205
+ // ✅ Shares cache with ProfilePage above
206
+ }
207
+ ```
208
+
209
+ **Zero manual cache management. Zero custom fetch logic. Production-ready data layer.**
210
+
11
211
  ## Installation
12
212
 
13
213
  ```sh
@@ -158,35 +158,35 @@ var ConfigManager;
158
158
  return { safe: true };
159
159
  }
160
160
  function safeCompileRegex(pattern, maxLength = 200) {
161
+ const isDevelopment = typeof process !== "undefined" && false;
161
162
  try {
162
163
  if (!pattern) {
163
- console.warn(`[SDK] DMCA pattern rejected: empty pattern`);
164
+ if (isDevelopment) ;
164
165
  return null;
165
166
  }
166
167
  if (pattern.length > maxLength) {
167
- console.warn(`[SDK] DMCA pattern rejected: length ${pattern.length} exceeds max ${maxLength} - pattern: ${pattern.substring(0, 50)}...`);
168
+ if (isDevelopment) ;
168
169
  return null;
169
170
  }
170
171
  const staticAnalysis = analyzeRedosRisk(pattern);
171
172
  if (!staticAnalysis.safe) {
172
- console.warn(`[SDK] DMCA pattern rejected: static analysis failed (${staticAnalysis.reason}) - pattern: ${pattern.substring(0, 50)}...`);
173
+ if (isDevelopment) ;
173
174
  return null;
174
175
  }
175
176
  let regex;
176
177
  try {
177
178
  regex = new RegExp(pattern);
178
179
  } catch (compileErr) {
179
- console.warn(`[SDK] DMCA pattern rejected: compilation failed - pattern: ${pattern.substring(0, 50)}...`, compileErr);
180
+ if (isDevelopment) ;
180
181
  return null;
181
182
  }
182
183
  const runtimeTest = testRegexPerformance(regex);
183
184
  if (!runtimeTest.safe) {
184
- console.warn(`[SDK] DMCA pattern rejected: runtime test failed (${runtimeTest.reason}) - pattern: ${pattern.substring(0, 50)}...`);
185
+ if (isDevelopment) ;
185
186
  return null;
186
187
  }
187
188
  return regex;
188
189
  } catch (err) {
189
- console.warn(`[SDK] DMCA pattern rejected: unexpected error - pattern: ${pattern.substring(0, 50)}...`, err);
190
190
  return null;
191
191
  }
192
192
  }
@@ -197,7 +197,8 @@ var ConfigManager;
197
197
  CONFIG.dmcaTagRegexes = tags.map((pattern) => safeCompileRegex(pattern)).filter((r) => r !== null);
198
198
  CONFIG.dmcaPatternRegexes = [];
199
199
  const rejectedTagCount = tags.length - CONFIG.dmcaTagRegexes.length;
200
- if (!CONFIG._dmcaInitialized) {
200
+ const isDevelopment = typeof process !== "undefined" && false;
201
+ if (!CONFIG._dmcaInitialized && isDevelopment) {
201
202
  console.log(`[SDK] DMCA configuration loaded:`);
202
203
  console.log(` - Accounts: ${accounts.length}`);
203
204
  console.log(` - Tag patterns: ${CONFIG.dmcaTagRegexes.length}/${tags.length} compiled (${rejectedTagCount} rejected)`);
@@ -205,8 +206,8 @@ var ConfigManager;
205
206
  if (rejectedTagCount > 0) {
206
207
  console.warn(`[SDK] ${rejectedTagCount} DMCA tag patterns were rejected due to security validation. Check warnings above for details.`);
207
208
  }
208
- CONFIG._dmcaInitialized = true;
209
209
  }
210
+ CONFIG._dmcaInitialized = true;
210
211
  }
211
212
  ConfigManager2.setDmcaLists = setDmcaLists;
212
213
  })(ConfigManager || (ConfigManager = {}));