@iblai/data-layer 0.3.1 → 1.0.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 +313 -7
- package/dist/index.d.ts +424 -424
- package/dist/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,24 +1,330 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @iblai/data-layer
|
|
2
|
+
|
|
3
|
+
A Redux Toolkit-based data layer package for IBL AI applications, providing centralized state management and API integrations using RTK Query.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @iblai/data-layer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
The data-layer package provides:
|
|
14
|
+
- **RTK Query API slices** for all IBL AI API endpoints
|
|
15
|
+
- **Redux store configuration** with pre-configured slices
|
|
16
|
+
- **Type-safe API hooks** for React components
|
|
17
|
+
- **Centralized state management** for auth, chat, subscriptions, and more
|
|
18
|
+
|
|
19
|
+
## Getting Started
|
|
20
|
+
|
|
21
|
+
### 1. Setup Redux Store
|
|
22
|
+
|
|
23
|
+
Wrap your application with the Redux Provider:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { Provider } from 'react-redux';
|
|
27
|
+
import { store } from '@iblai/data-layer';
|
|
28
|
+
|
|
29
|
+
function App() {
|
|
30
|
+
return (
|
|
31
|
+
<Provider store={store}>
|
|
32
|
+
<YourApp />
|
|
33
|
+
</Provider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Using API Hooks
|
|
39
|
+
|
|
40
|
+
The package provides auto-generated hooks for all API endpoints:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { useGetUserProfileQuery, useUpdateUserProfileMutation } from '@iblai/data-layer';
|
|
44
|
+
|
|
45
|
+
function UserProfile() {
|
|
46
|
+
// Query hook - automatically fetches data
|
|
47
|
+
const { data: profile, isLoading, error } = useGetUserProfileQuery();
|
|
48
|
+
|
|
49
|
+
// Mutation hook - for updates
|
|
50
|
+
const [updateProfile, { isLoading: isUpdating }] = useUpdateUserProfileMutation();
|
|
51
|
+
|
|
52
|
+
const handleSave = async (data) => {
|
|
53
|
+
await updateProfile(data).unwrap();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (isLoading) return <div>Loading...</div>;
|
|
57
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div>
|
|
61
|
+
<h1>{profile.name}</h1>
|
|
62
|
+
{/* Your profile UI */}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Available API Slices
|
|
69
|
+
|
|
70
|
+
### Core APIs
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import {
|
|
74
|
+
// User & Auth
|
|
75
|
+
useGetUserProfileQuery,
|
|
76
|
+
useUpdateUserProfileMutation,
|
|
77
|
+
useLoginMutation,
|
|
78
|
+
|
|
79
|
+
// Tenants
|
|
80
|
+
useGetTenantsQuery,
|
|
81
|
+
useGetTenantQuery,
|
|
82
|
+
useCreateTenantMutation,
|
|
83
|
+
|
|
84
|
+
// Platform
|
|
85
|
+
useGetPlatformConfigQuery,
|
|
86
|
+
} from '@iblai/data-layer';
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### AI & Chat APIs
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import {
|
|
93
|
+
// Mentors
|
|
94
|
+
useGetMentorsQuery,
|
|
95
|
+
useGetMentorQuery,
|
|
96
|
+
useCreateMentorMutation,
|
|
97
|
+
|
|
98
|
+
// Chat Sessions
|
|
99
|
+
useGetChatSessionsQuery,
|
|
100
|
+
useCreateChatSessionMutation,
|
|
101
|
+
|
|
102
|
+
// Memory
|
|
103
|
+
useGetMemoriesQuery,
|
|
104
|
+
useCreateMemoryMutation,
|
|
105
|
+
} from '@iblai/data-layer';
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Subscription APIs
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import {
|
|
112
|
+
// Stripe Integration
|
|
113
|
+
useGetSubscriptionQuery,
|
|
114
|
+
useCreateCheckoutSessionMutation,
|
|
115
|
+
useCreateCustomerPortalSessionMutation,
|
|
116
|
+
|
|
117
|
+
// Pricing
|
|
118
|
+
useGetPricingPlansQuery,
|
|
119
|
+
} from '@iblai/data-layer';
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Features
|
|
123
|
+
|
|
124
|
+
### Automatic Caching
|
|
125
|
+
|
|
126
|
+
RTK Query automatically caches API responses and handles cache invalidation:
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
// This query result is cached
|
|
130
|
+
const { data } = useGetUserProfileQuery();
|
|
131
|
+
|
|
132
|
+
// Subsequent calls use cached data
|
|
133
|
+
const { data: sameData } = useGetUserProfileQuery(); // No network request
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Optimistic Updates
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
const [updateProfile] = useUpdateUserProfileMutation();
|
|
140
|
+
|
|
141
|
+
const handleUpdate = async (newData) => {
|
|
142
|
+
try {
|
|
143
|
+
await updateProfile({
|
|
144
|
+
id: userId,
|
|
145
|
+
...newData,
|
|
146
|
+
}).unwrap();
|
|
147
|
+
// UI updates optimistically before API response
|
|
148
|
+
} catch (error) {
|
|
149
|
+
// Error handling
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Manual Cache Invalidation
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
import { useDispatch } from 'react-redux';
|
|
158
|
+
import { apiSlice } from '@iblai/data-layer';
|
|
159
|
+
|
|
160
|
+
function RefreshButton() {
|
|
161
|
+
const dispatch = useDispatch();
|
|
162
|
+
|
|
163
|
+
const handleRefresh = () => {
|
|
164
|
+
// Invalidate specific tags
|
|
165
|
+
dispatch(apiSlice.util.invalidateTags(['User']));
|
|
166
|
+
|
|
167
|
+
// Or reset entire API state
|
|
168
|
+
dispatch(apiSlice.util.resetApiState());
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
return <button onClick={handleRefresh}>Refresh</button>;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Polling
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
// Poll every 5 seconds
|
|
179
|
+
const { data } = useGetChatSessionsQuery(undefined, {
|
|
180
|
+
pollingInterval: 5000,
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Conditional Fetching
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
// Only fetch when userId is available
|
|
188
|
+
const { data } = useGetUserProfileQuery(userId, {
|
|
189
|
+
skip: !userId,
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Store Structure
|
|
194
|
+
|
|
195
|
+
The store includes the following slices:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
{
|
|
199
|
+
api: RTKQueryState, // All API data
|
|
200
|
+
auth: AuthState, // Authentication state
|
|
201
|
+
chat: ChatState, // Chat sessions and messages
|
|
202
|
+
files: FilesState, // File uploads and attachments
|
|
203
|
+
subscription: SubscriptionState, // Subscription info
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Accessing Store State
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
import { useSelector } from 'react-redux';
|
|
211
|
+
import { selectIsLoggedIn, selectCurrentUser } from '@iblai/data-layer';
|
|
212
|
+
|
|
213
|
+
function Header() {
|
|
214
|
+
const isLoggedIn = useSelector(selectIsLoggedIn);
|
|
215
|
+
const user = useSelector(selectCurrentUser);
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<header>
|
|
219
|
+
{isLoggedIn ? `Welcome ${user.name}` : 'Please log in'}
|
|
220
|
+
</header>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## TypeScript Support
|
|
226
|
+
|
|
227
|
+
All APIs are fully typed:
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import type { UserProfile, Tenant, Mentor } from '@iblai/data-layer';
|
|
231
|
+
|
|
232
|
+
const { data } = useGetUserProfileQuery();
|
|
233
|
+
// data is typed as UserProfile | undefined
|
|
234
|
+
|
|
235
|
+
const { data: tenant } = useGetTenantQuery(tenantId);
|
|
236
|
+
// tenant is typed as Tenant | undefined
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Error Handling
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
const { data, error, isError } = useGetUserProfileQuery();
|
|
243
|
+
|
|
244
|
+
if (isError) {
|
|
245
|
+
if ('status' in error) {
|
|
246
|
+
// RTK Query error
|
|
247
|
+
const errMsg = 'error' in error ? error.error : JSON.stringify(error.data);
|
|
248
|
+
return <div>Error: {errMsg}</div>;
|
|
249
|
+
} else {
|
|
250
|
+
// Serialized error
|
|
251
|
+
return <div>Error: {error.message}</div>;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Advanced Usage
|
|
257
|
+
|
|
258
|
+
### Custom Endpoints
|
|
259
|
+
|
|
260
|
+
Extend the API slice with custom endpoints:
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { apiSlice } from '@iblai/data-layer';
|
|
264
|
+
|
|
265
|
+
const extendedApi = apiSlice.injectEndpoints({
|
|
266
|
+
endpoints: (builder) => ({
|
|
267
|
+
getCustomData: builder.query({
|
|
268
|
+
query: () => '/custom-endpoint',
|
|
269
|
+
}),
|
|
270
|
+
}),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
export const { useGetCustomDataQuery } = extendedApi;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Prefetching
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import { useDispatch } from 'react-redux';
|
|
280
|
+
import { apiSlice } from '@iblai/data-layer';
|
|
281
|
+
|
|
282
|
+
function PrefetchExample() {
|
|
283
|
+
const dispatch = useDispatch();
|
|
284
|
+
|
|
285
|
+
const prefetchUserProfile = () => {
|
|
286
|
+
dispatch(
|
|
287
|
+
apiSlice.util.prefetch('getUserProfile', userId, { force: true })
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
return <button onMouseEnter={prefetchUserProfile}>Hover to prefetch</button>;
|
|
292
|
+
}
|
|
293
|
+
```
|
|
2
294
|
|
|
3
295
|
## Contributing
|
|
4
296
|
|
|
5
297
|
We welcome contributions! Please read our [contributing guidelines](CONTRIBUTING.md).
|
|
6
298
|
|
|
7
|
-
##
|
|
299
|
+
## Development
|
|
8
300
|
|
|
9
|
-
|
|
301
|
+
### Local Development Setup
|
|
10
302
|
|
|
11
|
-
|
|
303
|
+
When developing locally, use a local registry to publish packages:
|
|
12
304
|
|
|
13
305
|
```bash
|
|
14
306
|
make publish-local
|
|
15
307
|
```
|
|
16
308
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Don't forge to setup the `.npmrc` file to use the local registry.
|
|
309
|
+
Configure your `.npmrc`:
|
|
20
310
|
|
|
21
311
|
```bash
|
|
22
312
|
//localhost:4873/:_authToken=<token>
|
|
23
313
|
@iblai:registry=http://localhost:4873/
|
|
24
314
|
```
|
|
315
|
+
|
|
316
|
+
### Building
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
pnpm build
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Testing
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
pnpm test
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## License
|
|
329
|
+
|
|
330
|
+
ISC
|