@trainly/react 1.0.3 → 1.1.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 +136 -15
- package/dist/TrainlyProvider.d.ts +3 -1
- package/dist/TrainlyProvider.js +47 -13
- package/dist/api/TrainlyClient.d.ts +6 -0
- package/dist/api/TrainlyClient.js +119 -20
- package/dist/components/TrainlyChat.js +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/useTrainly.d.ts +1 -1
- package/dist/useTrainly.js +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,10 +1,94 @@
|
|
|
1
1
|
# @trainly/react
|
|
2
2
|
|
|
3
|
-
**Dead simple RAG integration for React apps**
|
|
3
|
+
**Dead simple RAG integration for React apps with V1 OAuth Authentication**
|
|
4
4
|
|
|
5
|
-
Go from `npm install` to working AI in under 5 minutes.
|
|
5
|
+
Go from `npm install` to working AI in under 5 minutes. Now supports direct OAuth integration with **permanent user subchats** and complete privacy protection.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 🆕 **NEW: V1 Trusted Issuer Authentication**
|
|
8
|
+
|
|
9
|
+
Use your existing OAuth provider (Clerk, Auth0, Cognito) directly with Trainly! Users get permanent private workspaces, and developers never see raw files or queries.
|
|
10
|
+
|
|
11
|
+
### V1 Quick Start
|
|
12
|
+
|
|
13
|
+
#### 1. Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @trainly/react
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
#### 2. Register Your OAuth App (One-time)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
curl -X POST "http://localhost:8000/v1/console/apps/register" \
|
|
23
|
+
-H "X-Admin-Token: admin_dev_token_123" \
|
|
24
|
+
-F "app_name=My App" \
|
|
25
|
+
-F "issuer=https://clerk.myapp.com" \
|
|
26
|
+
-F 'allowed_audiences=["my-clerk-frontend-api"]'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Save the `app_id` from the response!
|
|
30
|
+
|
|
31
|
+
#### 3. Setup with V1 (Clerk Example)
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// app/layout.tsx
|
|
35
|
+
import { ClerkProvider } from "@clerk/nextjs";
|
|
36
|
+
import { TrainlyProvider } from "@trainly/react";
|
|
37
|
+
|
|
38
|
+
export default function RootLayout({ children }) {
|
|
39
|
+
return (
|
|
40
|
+
<html>
|
|
41
|
+
<body>
|
|
42
|
+
<ClerkProvider>
|
|
43
|
+
<TrainlyProvider appId="your_app_id_from_step_2">
|
|
44
|
+
{children}
|
|
45
|
+
</TrainlyProvider>
|
|
46
|
+
</ClerkProvider>
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### 4. Use with OAuth Authentication
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// Any component
|
|
57
|
+
import { useAuth } from "@clerk/nextjs";
|
|
58
|
+
import { useTrainly } from "@trainly/react";
|
|
59
|
+
|
|
60
|
+
function MyComponent() {
|
|
61
|
+
const { getToken } = useAuth();
|
|
62
|
+
const { ask, connectWithOAuthToken } = useTrainly();
|
|
63
|
+
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
async function setupTrainly() {
|
|
66
|
+
const idToken = await getToken();
|
|
67
|
+
await connectWithOAuthToken(idToken);
|
|
68
|
+
}
|
|
69
|
+
setupTrainly();
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
const handleClick = async () => {
|
|
73
|
+
const answer = await ask("What files do I have?");
|
|
74
|
+
console.log(answer); // AI response from user's permanent private subchat!
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return <button onClick={handleClick}>Ask My AI</button>;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 🔒 **V1 Benefits**
|
|
82
|
+
|
|
83
|
+
- ✅ **Permanent User Data**: Same user = same private subchat forever
|
|
84
|
+
- ✅ **Complete Privacy**: Developer never sees user files or queries
|
|
85
|
+
- ✅ **Any OAuth Provider**: Clerk, Auth0, Cognito, Firebase, custom OIDC
|
|
86
|
+
- ✅ **Zero Migration**: Works with your existing OAuth setup
|
|
87
|
+
- ✅ **Simple Integration**: Just add `appId` and use `connectWithOAuthToken()`
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 🚀 Original Quick Start (Legacy)
|
|
8
92
|
|
|
9
93
|
### 1. Install
|
|
10
94
|
|
|
@@ -111,20 +195,45 @@ function App() {
|
|
|
111
195
|
### Authentication Modes
|
|
112
196
|
|
|
113
197
|
```tsx
|
|
114
|
-
// Mode 1:
|
|
198
|
+
// Mode 1: V1 Trusted Issuer (NEW - recommended for OAuth apps)
|
|
199
|
+
<TrainlyProvider appId="app_v1_12345" /> // Register via console API first
|
|
200
|
+
|
|
201
|
+
// Mode 2: App Secret (legacy - for multi-user apps)
|
|
115
202
|
<TrainlyProvider appSecret="as_secret_123" />
|
|
116
203
|
|
|
117
|
-
// Mode
|
|
204
|
+
// Mode 3: With user context (legacy)
|
|
118
205
|
<TrainlyProvider
|
|
119
206
|
appSecret="as_secret_123"
|
|
120
207
|
userId="user_123"
|
|
121
208
|
userEmail="user@example.com"
|
|
122
209
|
/>
|
|
123
210
|
|
|
124
|
-
// Mode
|
|
211
|
+
// Mode 4: Direct API key (legacy - simple apps)
|
|
125
212
|
<TrainlyProvider apiKey="tk_chat_id_key" />
|
|
126
213
|
```
|
|
127
214
|
|
|
215
|
+
### V1 OAuth Provider Examples
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
// With Clerk
|
|
219
|
+
<TrainlyProvider
|
|
220
|
+
appId="app_v1_clerk_123"
|
|
221
|
+
baseUrl="https://api.trainly.com"
|
|
222
|
+
/>
|
|
223
|
+
|
|
224
|
+
// With Auth0
|
|
225
|
+
<TrainlyProvider
|
|
226
|
+
appId="app_v1_auth0_456"
|
|
227
|
+
baseUrl="https://api.trainly.com"
|
|
228
|
+
/>
|
|
229
|
+
|
|
230
|
+
// With AWS Cognito
|
|
231
|
+
<TrainlyProvider
|
|
232
|
+
appId="app_v1_cognito_789"
|
|
233
|
+
baseUrl="https://api.trainly.com"
|
|
234
|
+
/>
|
|
235
|
+
```
|
|
236
|
+
|
|
128
237
|
### Component Customization
|
|
129
238
|
|
|
130
239
|
```tsx
|
|
@@ -177,6 +286,9 @@ const {
|
|
|
177
286
|
askWithCitations: (question: string) => Promise<{answer: string, citations: Citation[]}>,
|
|
178
287
|
upload: (file: File) => Promise<UploadResult>,
|
|
179
288
|
|
|
289
|
+
// NEW: V1 Authentication
|
|
290
|
+
connectWithOAuthToken: (idToken: string) => Promise<void>,
|
|
291
|
+
|
|
180
292
|
// State
|
|
181
293
|
isLoading: boolean,
|
|
182
294
|
isConnected: boolean,
|
|
@@ -198,22 +310,31 @@ const {
|
|
|
198
310
|
```tsx
|
|
199
311
|
interface TrainlyProviderProps {
|
|
200
312
|
children: React.ReactNode;
|
|
201
|
-
|
|
202
|
-
|
|
313
|
+
appId?: string; // NEW: V1 app ID from console registration
|
|
314
|
+
appSecret?: string; // Legacy: App secret from Trainly dashboard
|
|
315
|
+
apiKey?: string; // Legacy: Direct API key (alternative to appSecret)
|
|
203
316
|
baseUrl?: string; // Custom API URL (defaults to trainly.com)
|
|
204
|
-
userId?: string; // Your app's user ID
|
|
205
|
-
userEmail?: string; // Your app's user email
|
|
317
|
+
userId?: string; // Legacy: Your app's user ID
|
|
318
|
+
userEmail?: string; // Legacy: Your app's user email
|
|
206
319
|
}
|
|
207
320
|
```
|
|
208
321
|
|
|
209
322
|
## 🔍 Examples
|
|
210
323
|
|
|
211
|
-
|
|
324
|
+
See complete implementation examples in the [API Documentation](https://trainly.com/docs/v1-authentication).
|
|
325
|
+
|
|
326
|
+
## 🆚 **V1 vs Legacy Comparison**
|
|
327
|
+
|
|
328
|
+
| Feature | V1 Trusted Issuer | Legacy App Secret |
|
|
329
|
+
| -------------- | -------------------------------- | ------------------------- |
|
|
330
|
+
| **User Auth** | Your OAuth provider | Trainly OAuth flow |
|
|
331
|
+
| **User Data** | Permanent private subchat | Temporary or shared |
|
|
332
|
+
| **Privacy** | Complete (dev can't see files) | Limited |
|
|
333
|
+
| **Setup** | Register once, use OAuth tokens | Generate app secrets |
|
|
334
|
+
| **Migration** | Zero (uses existing OAuth) | Requires auth integration |
|
|
335
|
+
| **Permanence** | Same user = same subchat forever | Depends on implementation |
|
|
212
336
|
|
|
213
|
-
|
|
214
|
-
- **Custom Implementation** - Build your own UI
|
|
215
|
-
- **Multi-user App** - User-specific workspaces
|
|
216
|
-
- **File-focused App** - Document analysis focus
|
|
337
|
+
**Recommendation**: Use V1 for new apps and consider migrating existing apps for better privacy and user experience.
|
|
217
338
|
|
|
218
339
|
## 🛠️ Development
|
|
219
340
|
|
|
@@ -4,9 +4,11 @@ export interface TrainlyProviderProps {
|
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
appSecret?: string;
|
|
6
6
|
apiKey?: string;
|
|
7
|
+
appId?: string;
|
|
7
8
|
baseUrl?: string;
|
|
8
9
|
userId?: string;
|
|
9
10
|
userEmail?: string;
|
|
10
11
|
}
|
|
11
|
-
export declare function TrainlyProvider({ children, appSecret, apiKey,
|
|
12
|
+
export declare function TrainlyProvider({ children, appSecret, apiKey, appId, // NEW: For V1 authentication
|
|
13
|
+
baseUrl, userId, userEmail, }: TrainlyProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
12
14
|
export declare function useTrainlyContext(): TrainlyContextValue;
|
package/dist/TrainlyProvider.js
CHANGED
|
@@ -50,11 +50,14 @@ import { TrainlyClient } from "./api/TrainlyClient";
|
|
|
50
50
|
var TrainlyContext = React.createContext(undefined);
|
|
51
51
|
export function TrainlyProvider(_a) {
|
|
52
52
|
var _this = this;
|
|
53
|
-
var children = _a.children, appSecret = _a.appSecret, apiKey = _a.apiKey,
|
|
53
|
+
var children = _a.children, appSecret = _a.appSecret, apiKey = _a.apiKey, appId = _a.appId, // NEW: For V1 authentication
|
|
54
|
+
_b = _a.baseUrl, // NEW: For V1 authentication
|
|
55
|
+
baseUrl = _b === void 0 ? "http://localhost:8000" : _b, userId = _a.userId, userEmail = _a.userEmail;
|
|
54
56
|
var client = React.useState(function () {
|
|
55
57
|
return new TrainlyClient({
|
|
56
58
|
appSecret: appSecret,
|
|
57
59
|
apiKey: apiKey,
|
|
60
|
+
appId: appId, // NEW: Pass appId to client
|
|
58
61
|
baseUrl: baseUrl,
|
|
59
62
|
userId: userId,
|
|
60
63
|
userEmail: userEmail,
|
|
@@ -97,8 +100,38 @@ export function TrainlyProvider(_a) {
|
|
|
97
100
|
}
|
|
98
101
|
});
|
|
99
102
|
}); };
|
|
103
|
+
// NEW: V1 OAuth Token connection method
|
|
104
|
+
var connectWithOAuthToken = function (idToken) { return __awaiter(_this, void 0, void 0, function () {
|
|
105
|
+
var err_2;
|
|
106
|
+
return __generator(this, function (_a) {
|
|
107
|
+
switch (_a.label) {
|
|
108
|
+
case 0:
|
|
109
|
+
_a.trys.push([0, 2, 3, 4]);
|
|
110
|
+
setIsLoading(true);
|
|
111
|
+
setError(null);
|
|
112
|
+
return [4 /*yield*/, client.connectWithOAuthToken(idToken)];
|
|
113
|
+
case 1:
|
|
114
|
+
_a.sent();
|
|
115
|
+
setIsConnected(true);
|
|
116
|
+
return [3 /*break*/, 4];
|
|
117
|
+
case 2:
|
|
118
|
+
err_2 = _a.sent();
|
|
119
|
+
setError({
|
|
120
|
+
code: "V1_CONNECTION_FAILED",
|
|
121
|
+
message: "Failed to connect with OAuth token",
|
|
122
|
+
details: err_2,
|
|
123
|
+
});
|
|
124
|
+
setIsConnected(false);
|
|
125
|
+
throw err_2;
|
|
126
|
+
case 3:
|
|
127
|
+
setIsLoading(false);
|
|
128
|
+
return [7 /*endfinally*/];
|
|
129
|
+
case 4: return [2 /*return*/];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}); };
|
|
100
133
|
var ask = function (question) { return __awaiter(_this, void 0, void 0, function () {
|
|
101
|
-
var response,
|
|
134
|
+
var response, err_3, error_1;
|
|
102
135
|
return __generator(this, function (_a) {
|
|
103
136
|
switch (_a.label) {
|
|
104
137
|
case 0:
|
|
@@ -110,11 +143,11 @@ export function TrainlyProvider(_a) {
|
|
|
110
143
|
response = _a.sent();
|
|
111
144
|
return [2 /*return*/, response.answer];
|
|
112
145
|
case 2:
|
|
113
|
-
|
|
146
|
+
err_3 = _a.sent();
|
|
114
147
|
error_1 = {
|
|
115
148
|
code: "QUERY_FAILED",
|
|
116
149
|
message: "Failed to get answer",
|
|
117
|
-
details:
|
|
150
|
+
details: err_3,
|
|
118
151
|
};
|
|
119
152
|
setError(error_1);
|
|
120
153
|
throw error_1;
|
|
@@ -126,7 +159,7 @@ export function TrainlyProvider(_a) {
|
|
|
126
159
|
});
|
|
127
160
|
}); };
|
|
128
161
|
var askWithCitations = function (question) { return __awaiter(_this, void 0, void 0, function () {
|
|
129
|
-
var response,
|
|
162
|
+
var response, err_4, error_2;
|
|
130
163
|
return __generator(this, function (_a) {
|
|
131
164
|
switch (_a.label) {
|
|
132
165
|
case 0:
|
|
@@ -141,11 +174,11 @@ export function TrainlyProvider(_a) {
|
|
|
141
174
|
citations: response.citations || [],
|
|
142
175
|
}];
|
|
143
176
|
case 2:
|
|
144
|
-
|
|
177
|
+
err_4 = _a.sent();
|
|
145
178
|
error_2 = {
|
|
146
179
|
code: "QUERY_FAILED",
|
|
147
180
|
message: "Failed to get answer with citations",
|
|
148
|
-
details:
|
|
181
|
+
details: err_4,
|
|
149
182
|
};
|
|
150
183
|
setError(error_2);
|
|
151
184
|
throw error_2;
|
|
@@ -157,7 +190,7 @@ export function TrainlyProvider(_a) {
|
|
|
157
190
|
});
|
|
158
191
|
}); };
|
|
159
192
|
var upload = function (file) { return __awaiter(_this, void 0, void 0, function () {
|
|
160
|
-
var result,
|
|
193
|
+
var result, err_5, error_3;
|
|
161
194
|
return __generator(this, function (_a) {
|
|
162
195
|
switch (_a.label) {
|
|
163
196
|
case 0:
|
|
@@ -169,11 +202,11 @@ export function TrainlyProvider(_a) {
|
|
|
169
202
|
result = _a.sent();
|
|
170
203
|
return [2 /*return*/, result];
|
|
171
204
|
case 2:
|
|
172
|
-
|
|
205
|
+
err_5 = _a.sent();
|
|
173
206
|
error_3 = {
|
|
174
207
|
code: "UPLOAD_FAILED",
|
|
175
208
|
message: "Failed to upload file",
|
|
176
|
-
details:
|
|
209
|
+
details: err_5,
|
|
177
210
|
};
|
|
178
211
|
setError(error_3);
|
|
179
212
|
throw error_3;
|
|
@@ -185,7 +218,7 @@ export function TrainlyProvider(_a) {
|
|
|
185
218
|
});
|
|
186
219
|
}); };
|
|
187
220
|
var sendMessage = function (content) { return __awaiter(_this, void 0, void 0, function () {
|
|
188
|
-
var userMessage, response, assistantMessage_1,
|
|
221
|
+
var userMessage, response, assistantMessage_1, err_6;
|
|
189
222
|
return __generator(this, function (_a) {
|
|
190
223
|
switch (_a.label) {
|
|
191
224
|
case 0:
|
|
@@ -212,9 +245,9 @@ export function TrainlyProvider(_a) {
|
|
|
212
245
|
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [assistantMessage_1], false); });
|
|
213
246
|
return [3 /*break*/, 4];
|
|
214
247
|
case 3:
|
|
215
|
-
|
|
248
|
+
err_6 = _a.sent();
|
|
216
249
|
// Error is already set by askWithCitations
|
|
217
|
-
console.error("Failed to send message:",
|
|
250
|
+
console.error("Failed to send message:", err_6);
|
|
218
251
|
return [3 /*break*/, 4];
|
|
219
252
|
case 4: return [2 /*return*/];
|
|
220
253
|
}
|
|
@@ -227,6 +260,7 @@ export function TrainlyProvider(_a) {
|
|
|
227
260
|
ask: ask,
|
|
228
261
|
askWithCitations: askWithCitations,
|
|
229
262
|
upload: upload,
|
|
263
|
+
connectWithOAuthToken: connectWithOAuthToken, // NEW: V1 OAuth connection method
|
|
230
264
|
isLoading: isLoading,
|
|
231
265
|
isConnected: isConnected,
|
|
232
266
|
error: error,
|
|
@@ -7,7 +7,13 @@ export declare class TrainlyClient {
|
|
|
7
7
|
private config;
|
|
8
8
|
private scopedToken;
|
|
9
9
|
private currentUserId;
|
|
10
|
+
private isV1Mode;
|
|
10
11
|
constructor(config: TrainlyConfig);
|
|
12
|
+
/**
|
|
13
|
+
* NEW: Connect using V1 Trusted Issuer authentication with OAuth ID token
|
|
14
|
+
* This method allows users to authenticate directly with their OAuth provider tokens
|
|
15
|
+
*/
|
|
16
|
+
connectWithOAuthToken(idToken: string): Promise<void>;
|
|
11
17
|
connect(): Promise<void>;
|
|
12
18
|
ask(question: string, options?: {
|
|
13
19
|
includeCitations?: boolean;
|
|
@@ -49,8 +49,51 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
49
49
|
function TrainlyClient(config) {
|
|
50
50
|
this.scopedToken = null;
|
|
51
51
|
this.currentUserId = null;
|
|
52
|
+
this.isV1Mode = false;
|
|
52
53
|
this.config = config;
|
|
53
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* NEW: Connect using V1 Trusted Issuer authentication with OAuth ID token
|
|
57
|
+
* This method allows users to authenticate directly with their OAuth provider tokens
|
|
58
|
+
*/
|
|
59
|
+
TrainlyClient.prototype.connectWithOAuthToken = function (idToken) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
61
|
+
var response, error, profile;
|
|
62
|
+
return __generator(this, function (_a) {
|
|
63
|
+
switch (_a.label) {
|
|
64
|
+
case 0:
|
|
65
|
+
if (!this.config.appId) {
|
|
66
|
+
throw new Error("appId is required for V1 authentication.");
|
|
67
|
+
}
|
|
68
|
+
// For V1, we use the ID token directly - no need to provision
|
|
69
|
+
this.scopedToken = idToken;
|
|
70
|
+
this.isV1Mode = true;
|
|
71
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/me/profile"), {
|
|
72
|
+
headers: {
|
|
73
|
+
Authorization: "Bearer ".concat(idToken),
|
|
74
|
+
"X-App-ID": this.config.appId,
|
|
75
|
+
},
|
|
76
|
+
})];
|
|
77
|
+
case 1:
|
|
78
|
+
response = _a.sent();
|
|
79
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
80
|
+
return [4 /*yield*/, response.json()];
|
|
81
|
+
case 2:
|
|
82
|
+
error = _a.sent();
|
|
83
|
+
throw new Error("V1 authentication failed: ".concat(error.detail || response.statusText));
|
|
84
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
85
|
+
case 4:
|
|
86
|
+
profile = _a.sent();
|
|
87
|
+
this.currentUserId = profile.user_id;
|
|
88
|
+
console.log("✅ Connected to Trainly with V1 Trusted Issuer authentication");
|
|
89
|
+
console.log("\uD83D\uDCCB User ID: ".concat(profile.user_id));
|
|
90
|
+
console.log("\uD83D\uDCAC Chat ID: ".concat(profile.chat_id));
|
|
91
|
+
console.log("\uD83D\uDD12 OAuth Provider: ".concat(profile.issuer));
|
|
92
|
+
return [2 /*return*/];
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
54
97
|
TrainlyClient.prototype.connect = function () {
|
|
55
98
|
return __awaiter(this, void 0, void 0, function () {
|
|
56
99
|
var response, error, data;
|
|
@@ -99,14 +142,42 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
99
142
|
};
|
|
100
143
|
TrainlyClient.prototype.ask = function (question_1) {
|
|
101
144
|
return __awaiter(this, arguments, void 0, function (question, options) {
|
|
102
|
-
var url, headers, body, response, error, data;
|
|
145
|
+
var response_1, error, data_1, url, headers, body, response, error, data;
|
|
103
146
|
if (options === void 0) { options = {}; }
|
|
104
147
|
return __generator(this, function (_a) {
|
|
105
148
|
switch (_a.label) {
|
|
106
149
|
case 0:
|
|
107
150
|
if (!this.scopedToken) {
|
|
108
|
-
throw new Error("Not connected. Call connect() first.");
|
|
151
|
+
throw new Error("Not connected. Call connect() or connectWithOAuthToken() first.");
|
|
109
152
|
}
|
|
153
|
+
if (!(this.isV1Mode && this.config.appId)) return [3 /*break*/, 5];
|
|
154
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/me/chats/query"), {
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers: {
|
|
157
|
+
Authorization: "Bearer ".concat(this.scopedToken),
|
|
158
|
+
"X-App-ID": this.config.appId,
|
|
159
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
160
|
+
},
|
|
161
|
+
body: new URLSearchParams({
|
|
162
|
+
messages: JSON.stringify([{ role: "user", content: question }]),
|
|
163
|
+
response_tokens: "150",
|
|
164
|
+
}),
|
|
165
|
+
})];
|
|
166
|
+
case 1:
|
|
167
|
+
response_1 = _a.sent();
|
|
168
|
+
if (!!response_1.ok) return [3 /*break*/, 3];
|
|
169
|
+
return [4 /*yield*/, response_1.json()];
|
|
170
|
+
case 2:
|
|
171
|
+
error = _a.sent();
|
|
172
|
+
throw new Error("V1 query failed: ".concat(error.detail || response_1.statusText));
|
|
173
|
+
case 3: return [4 /*yield*/, response_1.json()];
|
|
174
|
+
case 4:
|
|
175
|
+
data_1 = _a.sent();
|
|
176
|
+
return [2 /*return*/, {
|
|
177
|
+
answer: data_1.answer,
|
|
178
|
+
citations: data_1.citations || [],
|
|
179
|
+
}];
|
|
180
|
+
case 5:
|
|
110
181
|
url = this.config.apiKey
|
|
111
182
|
? "".concat(this.config.baseUrl, "/v1/").concat(this.extractChatId(), "/answer_question")
|
|
112
183
|
: "".concat(this.config.baseUrl, "/v1/privacy/query");
|
|
@@ -129,15 +200,15 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
129
200
|
headers: headers,
|
|
130
201
|
body: JSON.stringify(body),
|
|
131
202
|
})];
|
|
132
|
-
case
|
|
203
|
+
case 6:
|
|
133
204
|
response = _a.sent();
|
|
134
|
-
if (!!response.ok) return [3 /*break*/,
|
|
205
|
+
if (!!response.ok) return [3 /*break*/, 8];
|
|
135
206
|
return [4 /*yield*/, response.json()];
|
|
136
|
-
case
|
|
207
|
+
case 7:
|
|
137
208
|
error = _a.sent();
|
|
138
209
|
throw new Error("Query failed: ".concat(error.detail || response.statusText));
|
|
139
|
-
case
|
|
140
|
-
case
|
|
210
|
+
case 8: return [4 /*yield*/, response.json()];
|
|
211
|
+
case 9:
|
|
141
212
|
data = _a.sent();
|
|
142
213
|
return [2 /*return*/, {
|
|
143
214
|
answer: data.answer,
|
|
@@ -149,20 +220,21 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
149
220
|
};
|
|
150
221
|
TrainlyClient.prototype.upload = function (file) {
|
|
151
222
|
return __awaiter(this, void 0, void 0, function () {
|
|
152
|
-
var formData, response, error, presignedResponse, error, _a, upload_url, upload_headers, formData, uploadResponse;
|
|
223
|
+
var formData, response, error, data, formData, response, error, presignedResponse, error, _a, upload_url, upload_headers, formData, uploadResponse;
|
|
153
224
|
return __generator(this, function (_b) {
|
|
154
225
|
switch (_b.label) {
|
|
155
226
|
case 0:
|
|
156
227
|
if (!this.scopedToken) {
|
|
157
|
-
throw new Error("Not connected. Call connect() first.");
|
|
228
|
+
throw new Error("Not connected. Call connect() or connectWithOAuthToken() first.");
|
|
158
229
|
}
|
|
159
|
-
if (!this.config.
|
|
230
|
+
if (!(this.isV1Mode && this.config.appId)) return [3 /*break*/, 5];
|
|
160
231
|
formData = new FormData();
|
|
161
232
|
formData.append("file", file);
|
|
162
|
-
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/
|
|
233
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/me/chats/files/upload"), {
|
|
163
234
|
method: "POST",
|
|
164
235
|
headers: {
|
|
165
|
-
Authorization: "Bearer ".concat(this.
|
|
236
|
+
Authorization: "Bearer ".concat(this.scopedToken),
|
|
237
|
+
"X-App-ID": this.config.appId,
|
|
166
238
|
},
|
|
167
239
|
body: formData,
|
|
168
240
|
})];
|
|
@@ -171,15 +243,42 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
171
243
|
if (!!response.ok) return [3 /*break*/, 3];
|
|
172
244
|
return [4 /*yield*/, response.json()];
|
|
173
245
|
case 2:
|
|
246
|
+
error = _b.sent();
|
|
247
|
+
throw new Error("V1 upload failed: ".concat(error.detail || response.statusText));
|
|
248
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
249
|
+
case 4:
|
|
250
|
+
data = _b.sent();
|
|
251
|
+
return [2 /*return*/, {
|
|
252
|
+
success: data.success,
|
|
253
|
+
filename: data.filename,
|
|
254
|
+
size: data.size_bytes,
|
|
255
|
+
message: data.message || "File uploaded to your permanent private subchat",
|
|
256
|
+
}];
|
|
257
|
+
case 5:
|
|
258
|
+
if (!this.config.apiKey) return [3 /*break*/, 9];
|
|
259
|
+
formData = new FormData();
|
|
260
|
+
formData.append("file", file);
|
|
261
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/").concat(this.extractChatId(), "/upload_file"), {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: {
|
|
264
|
+
Authorization: "Bearer ".concat(this.config.apiKey),
|
|
265
|
+
},
|
|
266
|
+
body: formData,
|
|
267
|
+
})];
|
|
268
|
+
case 6:
|
|
269
|
+
response = _b.sent();
|
|
270
|
+
if (!!response.ok) return [3 /*break*/, 8];
|
|
271
|
+
return [4 /*yield*/, response.json()];
|
|
272
|
+
case 7:
|
|
174
273
|
error = _b.sent();
|
|
175
274
|
throw new Error("Upload failed: ".concat(error.detail || response.statusText));
|
|
176
|
-
case
|
|
275
|
+
case 8: return [2 /*return*/, {
|
|
177
276
|
success: true,
|
|
178
277
|
filename: file.name,
|
|
179
278
|
size: file.size,
|
|
180
279
|
message: "File uploaded successfully",
|
|
181
280
|
}];
|
|
182
|
-
case
|
|
281
|
+
case 9: return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/privacy/upload/presigned-url"), {
|
|
183
282
|
method: "POST",
|
|
184
283
|
headers: {
|
|
185
284
|
"Content-Type": "application/json",
|
|
@@ -193,15 +292,15 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
193
292
|
file_type: file.type,
|
|
194
293
|
}),
|
|
195
294
|
})];
|
|
196
|
-
case
|
|
295
|
+
case 10:
|
|
197
296
|
presignedResponse = _b.sent();
|
|
198
|
-
if (!!presignedResponse.ok) return [3 /*break*/,
|
|
297
|
+
if (!!presignedResponse.ok) return [3 /*break*/, 12];
|
|
199
298
|
return [4 /*yield*/, presignedResponse.json()];
|
|
200
|
-
case
|
|
299
|
+
case 11:
|
|
201
300
|
error = _b.sent();
|
|
202
301
|
throw new Error("Failed to get upload URL: ".concat(error.detail || presignedResponse.statusText));
|
|
203
|
-
case
|
|
204
|
-
case
|
|
302
|
+
case 12: return [4 /*yield*/, presignedResponse.json()];
|
|
303
|
+
case 13:
|
|
205
304
|
_a = _b.sent(), upload_url = _a.upload_url, upload_headers = _a.upload_headers;
|
|
206
305
|
formData = new FormData();
|
|
207
306
|
formData.append("file", file);
|
|
@@ -210,7 +309,7 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
210
309
|
body: formData,
|
|
211
310
|
headers: __assign({}, upload_headers),
|
|
212
311
|
})];
|
|
213
|
-
case
|
|
312
|
+
case 14:
|
|
214
313
|
uploadResponse = _b.sent();
|
|
215
314
|
if (!uploadResponse.ok) {
|
|
216
315
|
throw new Error("Failed to upload file");
|
|
@@ -87,7 +87,7 @@ export function TrainlyChat(_a) {
|
|
|
87
87
|
var file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
88
88
|
if (file) {
|
|
89
89
|
// This would trigger upload and add a system message
|
|
90
|
-
|
|
90
|
+
// File selected for upload
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
93
|
var baseClasses = "\n flex flex-col border border-gray-200 rounded-lg overflow-hidden\n ".concat(theme === "dark" ? "bg-gray-900 text-white border-gray-700" : "bg-white text-gray-900", "\n ").concat(className, "\n ");
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface TrainlyConfig {
|
|
2
2
|
appSecret?: string;
|
|
3
3
|
apiKey?: string;
|
|
4
|
+
appId?: string;
|
|
4
5
|
baseUrl?: string;
|
|
5
6
|
userId?: string;
|
|
6
7
|
userEmail?: string;
|
|
@@ -9,6 +10,7 @@ export interface TrainlyProviderProps {
|
|
|
9
10
|
children: React.ReactNode;
|
|
10
11
|
appSecret?: string;
|
|
11
12
|
apiKey?: string;
|
|
13
|
+
appId?: string;
|
|
12
14
|
baseUrl?: string;
|
|
13
15
|
userId?: string;
|
|
14
16
|
userEmail?: string;
|
|
@@ -44,6 +46,7 @@ export interface TrainlyContextValue {
|
|
|
44
46
|
citations: Citation[];
|
|
45
47
|
}>;
|
|
46
48
|
upload: (file: File) => Promise<UploadResult>;
|
|
49
|
+
connectWithOAuthToken: (idToken: string) => Promise<void>;
|
|
47
50
|
isLoading: boolean;
|
|
48
51
|
isConnected: boolean;
|
|
49
52
|
error: TrainlyError | null;
|
package/dist/useTrainly.d.ts
CHANGED
package/dist/useTrainly.js
CHANGED
|
@@ -9,7 +9,7 @@ import { useTrainlyContext } from "./TrainlyProvider";
|
|
|
9
9
|
*
|
|
10
10
|
* const handleQuestion = async () => {
|
|
11
11
|
* const answer = await ask("What is photosynthesis?");
|
|
12
|
-
*
|
|
12
|
+
* // Handle the answer response
|
|
13
13
|
* };
|
|
14
14
|
*
|
|
15
15
|
* return <button onClick={handleQuestion}>Ask AI</button>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trainly/react",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Dead simple RAG integration for React apps",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Dead simple RAG integration for React apps with OAuth authentication",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"documents",
|
|
19
19
|
"react",
|
|
20
20
|
"trainly",
|
|
21
|
+
"oauth",
|
|
22
|
+
"authentication",
|
|
23
|
+
"privacy",
|
|
24
|
+
"clerk",
|
|
25
|
+
"auth0",
|
|
21
26
|
"retrieval-augmented-generation",
|
|
22
27
|
"semantic-search",
|
|
23
28
|
"document-chat"
|