@ecency/sdk 1.5.7 → 1.5.9

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
@@ -43,6 +43,20 @@ function useBroadcastMutation(mutationKey = [], username, operations, onSuccess
43
43
  }
44
44
  });
45
45
  }
46
+ var isDevelopment = (() => {
47
+ try {
48
+ return false;
49
+ } catch {
50
+ return false;
51
+ }
52
+ })();
53
+ var getHeliusApiKey = () => {
54
+ try {
55
+ return "fb1e2935-f911-4b1d-8e1c-3863f6879d42";
56
+ } catch {
57
+ return void 0;
58
+ }
59
+ };
46
60
  var CONFIG = {
47
61
  privateApiHost: "https://ecency.com",
48
62
  imageHost: "https://images.ecency.com",
@@ -66,7 +80,7 @@ var CONFIG = {
66
80
  consoleOnFailover: true
67
81
  }
68
82
  ),
69
- heliusApiKey: process.env.VITE_HELIUS_API_KEY,
83
+ heliusApiKey: getHeliusApiKey(),
70
84
  queryClient: new QueryClient(),
71
85
  plausibleHost: "https://pl.ecency.com",
72
86
  spkNode: "https://spk.good-karma.xyz",
@@ -158,35 +172,47 @@ var ConfigManager;
158
172
  return { safe: true };
159
173
  }
160
174
  function safeCompileRegex(pattern, maxLength = 200) {
161
- const isDevelopment = typeof process !== "undefined" && false;
162
175
  try {
163
176
  if (!pattern) {
164
- if (isDevelopment) ;
177
+ if (isDevelopment) {
178
+ console.warn(`[SDK] DMCA pattern rejected: empty pattern`);
179
+ }
165
180
  return null;
166
181
  }
167
182
  if (pattern.length > maxLength) {
168
- if (isDevelopment) ;
183
+ if (isDevelopment) {
184
+ console.warn(`[SDK] DMCA pattern rejected: length ${pattern.length} exceeds max ${maxLength} - pattern: ${pattern.substring(0, 50)}...`);
185
+ }
169
186
  return null;
170
187
  }
171
188
  const staticAnalysis = analyzeRedosRisk(pattern);
172
189
  if (!staticAnalysis.safe) {
173
- if (isDevelopment) ;
190
+ if (isDevelopment) {
191
+ console.warn(`[SDK] DMCA pattern rejected: static analysis failed (${staticAnalysis.reason}) - pattern: ${pattern.substring(0, 50)}...`);
192
+ }
174
193
  return null;
175
194
  }
176
195
  let regex;
177
196
  try {
178
197
  regex = new RegExp(pattern);
179
198
  } catch (compileErr) {
180
- if (isDevelopment) ;
199
+ if (isDevelopment) {
200
+ console.warn(`[SDK] DMCA pattern rejected: compilation failed - pattern: ${pattern.substring(0, 50)}...`, compileErr);
201
+ }
181
202
  return null;
182
203
  }
183
204
  const runtimeTest = testRegexPerformance(regex);
184
205
  if (!runtimeTest.safe) {
185
- if (isDevelopment) ;
206
+ if (isDevelopment) {
207
+ console.warn(`[SDK] DMCA pattern rejected: runtime test failed (${runtimeTest.reason}) - pattern: ${pattern.substring(0, 50)}...`);
208
+ }
186
209
  return null;
187
210
  }
188
211
  return regex;
189
212
  } catch (err) {
213
+ if (isDevelopment) {
214
+ console.warn(`[SDK] DMCA pattern rejected: unexpected error - pattern: ${pattern.substring(0, 50)}...`, err);
215
+ }
190
216
  return null;
191
217
  }
192
218
  }
@@ -197,7 +223,6 @@ var ConfigManager;
197
223
  CONFIG.dmcaTagRegexes = tags.map((pattern) => safeCompileRegex(pattern)).filter((r) => r !== null);
198
224
  CONFIG.dmcaPatternRegexes = [];
199
225
  const rejectedTagCount = tags.length - CONFIG.dmcaTagRegexes.length;
200
- const isDevelopment = typeof process !== "undefined" && false;
201
226
  if (!CONFIG._dmcaInitialized && isDevelopment) {
202
227
  console.log(`[SDK] DMCA configuration loaded:`);
203
228
  console.log(` - Accounts: ${accounts.length}`);