onairos 2.0.1 → 2.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onairos",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "dependencies": {
5
5
  "@anthropic-ai/sdk": "^0.24.3",
6
6
  "@google/generative-ai": "^0.15.0",
@@ -95,7 +95,12 @@
95
95
  "react": "^18.2.0",
96
96
  "react-dom": "^18.2.0",
97
97
  "react-native": ">=0.69.0",
98
- "tailwindcss": "^3.3.5"
98
+ "tailwindcss": "^3.3.5",
99
+ "ajv": "^8.12.0",
100
+ "@anthropic-ai/sdk": "^0.24.3",
101
+ "@google/generative-ai": "^0.15.0",
102
+ "@pinecone-database/pinecone": "^2.2.2",
103
+ "openai": "^4.52.7"
99
104
  },
100
105
  "description": "The Onairos Library is a collection of functions that enable Applications to connect and communicate data with Onairos Identities via User Authorization. Integration for developers is designed to be seamless, simple and effective for all applications",
101
106
  "main": "dist/onairos.bundle.js",
@@ -1,18 +1,18 @@
1
1
  import React, { useState, useEffect, useRef } from 'react';
2
2
  import UniversalOnboarding from '../components/UniversalOnboarding.js';
3
3
  import IndividualConnection from './components/IndividualConnection';
4
+ import onairosLogo from './icons/onairos_logo.png';
4
5
 
5
6
  /**
6
7
  * DataRequestPage Component
7
8
  * Displays different data requests and handles user interactions
8
9
  */
9
- const DataRequestPage = ({ requestData = {}, dataRequester = 'App', proofMode = false, domain = '' }) => {
10
+ const DataRequestPage = ({ requestData = {}, dataRequester = 'App', proofMode = false, domain = '', appIcon = '' }) => {
10
11
  const [loading, setLoading] = useState(true);
11
12
  const [activeModels, setActiveModels] = useState([]);
12
13
  const [granted, setGranted] = useState(0);
13
14
  const [allowSubmit, setAllowSubmit] = useState(false);
14
- const [avatar, setAvatar] = useState(false);
15
- const [traits, setTraits] = useState(false);
15
+ const [userConnections, setUserConnections] = useState(['instagram', 'youtube', 'email']);
16
16
  const [selectedRequests, setSelectedRequests] = useState({});
17
17
  const selectedConnections = useRef([]);
18
18
  const userSub = useRef(null);
@@ -36,7 +36,7 @@ const DataRequestPage = ({ requestData = {}, dataRequester = 'App', proofMode =
36
36
  await new Promise(resolve => setTimeout(resolve, 1000));
37
37
 
38
38
  // Sample active models - this would come from your backend
39
- setActiveModels(['Personality']);
39
+ setActiveModels(['Profile', 'User Memories']);
40
40
  setLoading(false);
41
41
  } catch (error) {
42
42
  console.error('Error loading data:', error);
@@ -151,90 +151,128 @@ const DataRequestPage = ({ requestData = {}, dataRequester = 'App', proofMode =
151
151
  }
152
152
 
153
153
  return (
154
- <div className="min-h-screen bg-gray-50">
154
+ <div className="min-h-screen bg-gray-100">
155
155
  {loading ? (
156
156
  <div className="flex items-center justify-center min-h-screen">
157
157
  <div className="animate-spin h-8 w-8 border-2 border-blue-600 rounded-full border-t-transparent"></div>
158
158
  </div>
159
- ) : (activeModels.length === 0 ? (
159
+ ) : activeModels.length === 0 ? (
160
160
  <UniversalOnboarding appIcon="https://onairos.sirv.com/Images/OnairosBlack.png" appName={dataRequester}/>
161
161
  ) : (
162
- <div className="max-w-md mx-auto p-4 space-y-2">
163
- <header className="border space-y-4 bg-white p-4 rounded-lg outline-2 outline-black/10 shadow-sm">
164
- <h1 className="text-lg font-bold text-black">Data Requests from {dataRequester}</h1>
162
+ <div className="max-w-md mx-auto p-6 space-y-4">
163
+ <header className="bg-white p-6 rounded-xl shadow-md">
164
+ <div className="flex items-center justify-between mb-6">
165
+ <div className="flex items-center space-x-2">
166
+ <img src={onairosLogo} alt="Onairos Logo" className="w-8 h-8" />
167
+ <div className="text-gray-400 mx-2">→</div>
168
+ {appIcon ? (
169
+ <img src={appIcon} alt={`${dataRequester} Logo`} className="w-8 h-8 rounded-full" />
170
+ ) : (
171
+ <div className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center">
172
+ <span className="text-gray-600 text-xs font-bold">{dataRequester.charAt(0)}</span>
173
+ </div>
174
+ )}
175
+ </div>
176
+ <h2 className="text-lg font-bold text-gray-800">{dataRequester}</h2>
177
+ </div>
178
+
179
+ <h1 className="text-xl font-bold text-gray-800 mb-4">Data Access Request</h1>
180
+ <p className="text-gray-600 mb-6">Select the data you want to share with {dataRequester}</p>
181
+
165
182
  <div className="flex items-center justify-between gap-4">
166
183
  <button
167
184
  onClick={rejectDataRequest}
168
- className="border w-full border-2 border-black/10 hover:bg-gray-50 text-black font-medium py-2 px-4 rounded"
185
+ className="border w-full border border-gray-300 hover:bg-gray-50 text-gray-700 font-medium py-3 px-4 rounded-lg transition-colors"
169
186
  >
170
- Reject All
187
+ Decline
171
188
  </button>
172
189
  <button
173
190
  disabled={!allowSubmit}
174
191
  onClick={sendDataRequest}
175
- className="w-full bg-black hover:bg-black/90 text-white font-medium py-2 px-4 rounded"
192
+ className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
176
193
  >
177
- Confirm ({granted})
194
+ Approve {granted > 0 && `(${granted})`}
178
195
  </button>
179
196
  </div>
180
197
  </header>
181
198
 
182
- <div className="space-y-2">
183
- {activeModels.length === 0 ? (
184
- <div className="flex flex-col items-center justify-center p-8 space-y-4 rounded-lg bg-white border-2 border-black/10">
185
- <img src="https://onairos.sirv.com/Images/OnairosBlack.png" alt="Logo" className="w-20 h-20" />
186
- <p className="text-center text-sm text-black/70">
187
- Please connect{" "}
188
- <a href="https://onairos.uk/connections" className="text-black font-medium hover:underline">
189
- Onairos
190
- </a>{" "}
191
- Personality to send {dataRequester} your data
192
- </p>
193
- </div>
194
- ) : (
195
- Object.keys(requestData)
196
- .sort((a, b) => {
197
- const aIsActive = activeModels.includes(requestData[a].type)
198
- const bIsActive = activeModels.includes(requestData[b].type)
199
-
200
- if (requestData[a].type === "Avatar") return 1
201
- if (requestData[b].type === "Avatar") return -1
202
- if (requestData[b].type === "Traits") return 1
203
- if (requestData[a].type === "Traits") return -1
204
- if (aIsActive && !bIsActive) return -1
205
- if (bIsActive && !aIsActive) return 1
206
- return 0
207
- })
208
- .map((key, index) => {
209
- const product = requestData[key]
210
- const active =
211
- product.type === "Personality"
212
- ? activeModels.includes(product.type)
213
- : product.type === "Avatar"
214
- ? avatar
215
- : product.type === "Traits"
216
- ? traits
217
- : false
199
+ <div className="space-y-3">
200
+ {/* Only show Profile and User Memories */}
201
+ {['Profile', 'User Memories'].map((dataType, index) => {
202
+ const key = dataType.toLowerCase().replace(' ', '_');
203
+ const product = {
204
+ type: dataType,
205
+ descriptions: dataType === 'Profile' ?
206
+ 'Basic profile information and preferences' :
207
+ 'Your personal context and memory data',
208
+ reward: dataType === 'Profile' ?
209
+ 'Personalized experience' :
210
+ 'Contextual understanding of your preferences'
211
+ };
212
+
213
+ return (
214
+ <IndividualConnection
215
+ key={key}
216
+ active={true}
217
+ title={product.type}
218
+ id={product}
219
+ number={index}
220
+ descriptions={product.descriptions}
221
+ rewards={product.reward}
222
+ size={key}
223
+ changeGranted={changeGranted}
224
+ onSelectionChange={(isSelected) =>
225
+ handleConnectionSelection(dataRequester, key, index, product.type, product.reward, isSelected)
226
+ }
227
+ />
228
+ );
229
+ })}
230
+
231
+ {/* User Connections Section */}
232
+ <div className="bg-white p-4 rounded-xl shadow-sm mt-4">
233
+ <h3 className="text-sm font-semibold text-gray-700 mb-3">Your Connected Services</h3>
234
+ <div className="flex items-center space-x-3">
235
+ {userConnections.map((connection, index) => {
236
+ const getConnectionIcon = (type) => {
237
+ switch(type) {
238
+ case 'instagram':
239
+ return (
240
+ <div className="w-10 h-10 rounded-full bg-gradient-to-tr from-purple-500 via-pink-500 to-yellow-500 flex items-center justify-center">
241
+ <span className="text-white text-xs">IG</span>
242
+ </div>
243
+ );
244
+ case 'youtube':
245
+ return (
246
+ <div className="w-10 h-10 rounded-full bg-red-600 flex items-center justify-center">
247
+ <span className="text-white text-xs">YT</span>
248
+ </div>
249
+ );
250
+ case 'email':
251
+ return (
252
+ <div className="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center">
253
+ <span className="text-white text-xs">@</span>
254
+ </div>
255
+ );
256
+ default:
257
+ return (
258
+ <div className="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
259
+ <span className="text-gray-600 text-xs">{type.charAt(0).toUpperCase()}</span>
260
+ </div>
261
+ );
262
+ }
263
+ };
264
+
218
265
  return (
219
- <IndividualConnection
220
- key={key}
221
- active={active}
222
- title={product.type}
223
- id={product}
224
- number={index}
225
- descriptions={product.descriptions}
226
- rewards={product.reward}
227
- size={key}
228
- changeGranted={changeGranted}
229
- onSelectionChange={(isSelected) =>
230
- handleConnectionSelection(dataRequester, key, index, product.type, product.reward, isSelected)
231
- }
232
- />
233
- )
234
- })
235
- )}
266
+ <div key={index} className="flex flex-col items-center">
267
+ {getConnectionIcon(connection)}
268
+ <span className="text-xs text-gray-600 mt-1">{connection}</span>
269
+ </div>
270
+ );
271
+ })}
272
+ </div>
273
+ </div>
236
274
  </div>
237
- </div>)
275
+ </div>
238
276
  )}
239
277
  </div>
240
278
  );
@@ -1,17 +1,11 @@
1
1
  import React from 'react';
2
- import Sentiment from '../icons/Sentiment.png';
3
- import Avatar from '../icons/Avatar.png';
4
- import Avatar2 from '../icons/Avatar2.png';
5
- import Trait from '../icons/Trait.png';
6
- import { Checkbox } from "@/components/ui/checkbox";
7
- import { Label } from "@/components/ui/label";
8
2
 
9
3
  /**
10
4
  * Box Component
11
- * Displays a checkbox item for data access requests with appropriate icons
5
+ * Displays a checkbox item for data access requests
12
6
  */
13
7
  const Box = (props) => {
14
- const selectShortlistedApplicant = (e) => {
8
+ const handleChange = (e) => {
15
9
  const checked = e.target.checked;
16
10
  console.log(`Checkbox ${props.title} is now: ${checked ? 'checked' : 'unchecked'}`);
17
11
  if (checked) {
@@ -21,46 +15,39 @@ const Box = (props) => {
21
15
  props.setSelected(false);
22
16
  props.changeGranted(-1);
23
17
  }
24
- };
25
-
26
- const Insight = (props.title === "Avatar") ? 'Avatar' : (props.title === "Traits") ? 'Personality Traits' : 'Persona';
27
-
28
- const getIcon = () => {
29
- switch (props.title) {
30
- case "Traits":
31
- return <img src={Trait || "/placeholder.svg"} alt="Traits" className="w-5 h-5" />;
32
- case "Avatar":
33
- return <img src={Avatar2 || "/placeholder.svg"} alt="Avatar" className="w-5 h-5" />;
34
- default:
35
- return <img src={Sentiment || "/placeholder.svg"} alt="Interest" className="w-5 h-5" />;
36
- }
18
+
19
+ props.onSelectionChange(checked);
37
20
  };
38
21
 
39
22
  return (
40
- <div className="space-y-4">
41
- <div className="flex items-start space-x-3">
42
- <Checkbox
43
- id={`request-${props.number}`}
44
- disabled={!props.active}
45
- onCheckedChange={(checked) => {
46
- selectShortlistedApplicant({ target: { checked } });
47
- props.onSelectionChange(checked);
48
- }}
49
- className={`h-5 w-5 ${!props.active ? "cursor-not-allowed" : ""}`}
50
- />
51
- <Label
52
- htmlFor={`request-${props.number}`}
53
- className="flex items-center space-x-3 text-sm font-medium text-black peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
54
- >
55
- <div className="p-1 bg-gray-50 rounded-md">{getIcon()}</div>
56
- <span>Access your {props.title}</span>
57
- </Label>
58
- </div>
59
-
23
+ <div className="relative inline-flex items-center">
24
+ <input
25
+ type="checkbox"
26
+ id={`request-${props.number}`}
27
+ disabled={!props.active}
28
+ onChange={handleChange}
29
+ className={`
30
+ appearance-none w-5 h-5 border rounded
31
+ ${!props.active ? 'border-gray-300 bg-gray-100 cursor-not-allowed' : 'border-blue-500 cursor-pointer'}
32
+ checked:bg-blue-600 checked:border-blue-600
33
+ focus:outline-none focus:ring-2 focus:ring-blue-500/30
34
+ transition-colors
35
+ `}
36
+ />
37
+ <svg
38
+ className="absolute left-0.5 top-0.5 w-4 h-4 text-white pointer-events-none opacity-0 peer-checked:opacity-100"
39
+ fill="none"
40
+ stroke="currentColor"
41
+ viewBox="0 0 24 24"
42
+ xmlns="http://www.w3.org/2000/svg"
43
+ >
44
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M5 13l4 4L19 7"></path>
45
+ </svg>
46
+
60
47
  {!props.active && (
61
- <p className="text-xs text-red-600 font-medium ml-8">
62
- Please create your Personality model to access this Grant Request
63
- </p>
48
+ <span className="ml-2 text-xs text-red-500 font-medium">
49
+ Not available
50
+ </span>
64
51
  )}
65
52
  </div>
66
53
  );
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from 'react';
2
2
  import Box from './Box';
3
- import { Card } from "@/components/ui/card";
4
3
 
5
4
  /**
6
5
  * IndividualConnection Component
@@ -14,41 +13,75 @@ function IndividualConnection(props) {
14
13
  props.onSelectionChange(isSelected);
15
14
  };
16
15
 
17
- // The insight type based on title
18
- const Insight = (props.title === "Avatar") ? 'Avatar' : (props.title === "Traits") ? 'Personality Traits' : 'Persona';
16
+ // Get icon based on data type
17
+ const getDataTypeIcon = () => {
18
+ switch(props.title) {
19
+ case "Profile":
20
+ return (
21
+ <div className="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center">
22
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-blue-600" viewBox="0 0 20 20" fill="currentColor">
23
+ <path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
24
+ </svg>
25
+ </div>
26
+ );
27
+ case "User Memories":
28
+ return (
29
+ <div className="w-8 h-8 rounded-full bg-purple-100 flex items-center justify-center">
30
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-purple-600" viewBox="0 0 20 20" fill="currentColor">
31
+ <path d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z" />
32
+ </svg>
33
+ </div>
34
+ );
35
+ default:
36
+ return (
37
+ <div className="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center">
38
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-gray-600" viewBox="0 0 20 20" fill="currentColor">
39
+ <path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
40
+ </svg>
41
+ </div>
42
+ );
43
+ }
44
+ };
19
45
 
20
46
  return (
21
- <Card className="overflow-hidden outline-2 outline-black/10 bg-white shadow-sm hover:shadow-md transition-all">
22
- <div className="p-4 space-y-2">
23
- <div className="flex items-start justify-between">
24
- <Box
25
- active={props.active}
26
- onSelectionChange={handleSelectionChange}
27
- changeGranted={props.changeGranted}
28
- setSelected={setSelected}
29
- number={props.number + 1}
30
- type={"Test"}
31
- title={props.title}
32
- />
33
- </div>
34
-
35
- {props.descriptions && props.title !== "Avatar" && (
36
- <div className="space-y-2 border-t pt-3">
37
- <div className="flex flex-col space-y-1">
38
- <span className="text-xs font-semibold text-black/70">Intent</span>
39
- <span className="text-sm text-black">{props.descriptions}</span>
47
+ <div className="bg-white rounded-xl shadow-sm hover:shadow-md transition-all overflow-hidden">
48
+ <div className="p-5">
49
+ <div className="flex items-start space-x-4">
50
+ {getDataTypeIcon()}
51
+ <div className="flex-1">
52
+ <div className="flex items-center justify-between">
53
+ <h3 className="font-medium text-gray-800">{props.title}</h3>
54
+ <Box
55
+ active={props.active}
56
+ onSelectionChange={handleSelectionChange}
57
+ changeGranted={props.changeGranted}
58
+ setSelected={setSelected}
59
+ number={props.number + 1}
60
+ type={"Test"}
61
+ title={props.title}
62
+ />
40
63
  </div>
64
+
65
+ {props.descriptions && (
66
+ <div className="mt-2">
67
+ <p className="text-sm text-gray-600">{props.descriptions}</p>
68
+ </div>
69
+ )}
41
70
  </div>
42
- )}
43
-
71
+ </div>
72
+
44
73
  {props.rewards && (
45
- <div className="flex flex-col space-y-1 border-t pt-3">
46
- <span className="text-xs font-semibold text-black/70">Rewards</span>
47
- <span className="text-sm text-black">{props.rewards}</span>
74
+ <div className="mt-3 pt-3 border-t border-gray-100">
75
+ <div className="flex items-center">
76
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-yellow-500 mr-2" viewBox="0 0 20 20" fill="currentColor">
77
+ <path fillRule="evenodd" d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z" clipRule="evenodd" />
78
+ </svg>
79
+ <span className="text-xs text-gray-500">Benefit: <span className="text-gray-700">{props.rewards}</span></span>
80
+ </div>
48
81
  </div>
49
82
  )}
50
83
  </div>
51
- </Card>
84
+ </div>
52
85
  );
53
86
  }
54
87
 
@@ -38,7 +38,7 @@ function getPopupUrl() {
38
38
  * Creates popup content dynamically as fallback
39
39
  */
40
40
  function createDynamicPopupContent(data) {
41
- const { requestData = [], webpageName = 'App', userData = {}, autoFetch = true } = data;
41
+ const { requestData = [], webpageName = 'App', userData = {}, autoFetch = true, appIcon = null } = data;
42
42
 
43
43
  const defaultDataTypes = [
44
44
  { id: 'email', name: 'Email Address', description: 'Your email for account identification', icon: '📧' },
@@ -74,6 +74,12 @@ function createDynamicPopupContent(data) {
74
74
  <div class="max-w-md mx-auto bg-white rounded-lg shadow-lg">
75
75
  <div class="p-6">
76
76
  <div class="text-center mb-6">
77
+ <div class="flex items-center justify-center space-x-2 mb-4">
78
+ <img src="https://onairos.sirv.com/Images/OnairosBlack.png" alt="Onairos Logo" class="w-8 h-8">
79
+ <div class="text-gray-400 mx-2">→</div>
80
+ ${appIcon ? `<img src="${appIcon}" alt="${webpageName} Logo" class="w-8 h-8 rounded-full">` :
81
+ `<div class="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center"><span class="text-gray-600 text-xs font-bold">${webpageName.charAt(0)}</span></div>`}
82
+ </div>
77
83
  <h2 class="text-2xl font-bold text-gray-900 mb-2">Data Request</h2>
78
84
  <p class="text-gray-600">${webpageName} is requesting access to your data</p>
79
85
  </div>