@welshare/react 0.0.1-alpha.1
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/LICENSE +7 -0
- package/README.md +124 -0
- package/dist/esm/components/connect-button.d.ts +6 -0
- package/dist/esm/components/connect-button.d.ts.map +1 -0
- package/dist/esm/components/connect-button.js +58 -0
- package/dist/esm/hooks/use-welshare.d.ts +10 -0
- package/dist/esm/hooks/use-welshare.d.ts.map +1 -0
- package/dist/esm/hooks/use-welshare.js +111 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/types.d.ts +32 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +1 -0
- package/dist/node_modules/@welshare/react/.gitignore +6 -0
- package/dist/node_modules/@welshare/react/.npmignore +34 -0
- package/dist/node_modules/@welshare/react/.tshy/build.json +8 -0
- package/dist/node_modules/@welshare/react/.tshy/esm.json +16 -0
- package/dist/node_modules/@welshare/react/LICENSE +7 -0
- package/dist/node_modules/@welshare/react/README.md +124 -0
- package/dist/node_modules/@welshare/react/dist/esm/components/connect-button.d.ts +6 -0
- package/dist/node_modules/@welshare/react/dist/esm/components/connect-button.d.ts.map +1 -0
- package/dist/node_modules/@welshare/react/dist/esm/components/connect-button.js +58 -0
- package/dist/node_modules/@welshare/react/dist/esm/hooks/use-welshare.d.ts +10 -0
- package/dist/node_modules/@welshare/react/dist/esm/hooks/use-welshare.d.ts.map +1 -0
- package/dist/node_modules/@welshare/react/dist/esm/hooks/use-welshare.js +111 -0
- package/dist/node_modules/@welshare/react/dist/esm/index.d.ts +7 -0
- package/dist/node_modules/@welshare/react/dist/esm/index.d.ts.map +1 -0
- package/dist/node_modules/@welshare/react/dist/esm/index.js +10 -0
- package/dist/node_modules/@welshare/react/dist/esm/package.json +3 -0
- package/dist/node_modules/@welshare/react/dist/esm/types.d.ts +32 -0
- package/dist/node_modules/@welshare/react/dist/esm/types.d.ts.map +1 -0
- package/dist/node_modules/@welshare/react/dist/esm/types.js +1 -0
- package/dist/node_modules/@welshare/react/eslint.config.mjs +4 -0
- package/dist/node_modules/@welshare/react/package.json +88 -0
- package/dist/node_modules/@welshare/react/src/components/connect-button.tsx +99 -0
- package/dist/node_modules/@welshare/react/src/hooks/use-welshare.ts +148 -0
- package/dist/node_modules/@welshare/react/src/index.ts +13 -0
- package/dist/node_modules/@welshare/react/src/types.ts +37 -0
- package/dist/node_modules/@welshare/react/tsconfig.json +21 -0
- package/package.json +87 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright © 2025 Welshare Health UG (haftungsbeschränkt) 2025
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @welshare/react
|
|
2
|
+
|
|
3
|
+
### Disclaimer, notes on maturity
|
|
4
|
+
|
|
5
|
+
This library is in Alpha / demo state at this moment. We're using it to review the security aspects while data is in transfer and in rest. There's absolutely no guarantee or warrant that at this point any data is safe. All data can be lost at any time - even though we're using resources that puts decentralization and resilience values to the front. Be **very** careful if you're integrating this into user facing code. Welshare Health wallets are controlled by cryptographic material which _can_ be stored in non custodial / MPC environments (Privy). While that's considered very safe, we can't guarantee at this point that we've already got each aspect of inter application communication or key derivation features right, so don't connect wallets that store significant value with the welshare wallet yet.
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
This is a React library that helps integrating with Welshare's sovereign data sharing platform. This package provides React hooks and components to connect applications with Welshare's wallet for secure data submission.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @welshare/react
|
|
15
|
+
# or
|
|
16
|
+
yarn add @welshare/react
|
|
17
|
+
# or
|
|
18
|
+
pnpm add @welshare/react
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Peer Dependencies
|
|
22
|
+
|
|
23
|
+
This package requires React 19+ as a peer dependency.
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
|
|
27
|
+
You need to register an app identifier using the Welshare Wallet frontend first: https://wallet.welshare.app/application. We're referring to this as `your-application-id` from here on.
|
|
28
|
+
|
|
29
|
+
If you want to submit questionnaire data, your application must first register a new questionnaire definition. You can also reuse an existing questionnaire id to let users contribute responses to another app's questionaire, but that's not highly encouraged at this point.
|
|
30
|
+
|
|
31
|
+
## Data Submissions
|
|
32
|
+
|
|
33
|
+
At the moment there are only two supported submission types: Fhir compatible QuestionnaireResponses and our custom "Reflex" app submissions. Both types are identified by schema uids that are accessible on the `Schemas` export.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
export const Schemas = {
|
|
37
|
+
QuestionnaireResponse: "b14b538f-7de3-4767-ad77-464d755d78bd"
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To submit questionnaires using custom frontends, you'll use the `useWelshare` hook to open a wallet dialog that lets your application talk to the user's connected wallets (using derived storage keys). All communication with the Welshare infrastructure happens inside that browser window.
|
|
42
|
+
|
|
43
|
+
## Code Sample
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { ConnectWelshareButton, Schemas, useWelshare } from "@welshare/react";
|
|
47
|
+
|
|
48
|
+
export function QuestionnaireForm() {
|
|
49
|
+
const { isConnected, openWallet, submitData } = useWelshare({
|
|
50
|
+
applicationId: <your-application-id>,
|
|
51
|
+
environment: "development", //optional, at the moment the environment is always development
|
|
52
|
+
callbacks: {
|
|
53
|
+
onUploaded: (payload) => console.log('Data uploaded:', payload),
|
|
54
|
+
onError: (error) => console.error('Error:', error),
|
|
55
|
+
onSessionReady: (storageKey) => console.log('Session ready:', storageKey),
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const handleSubmit = () => {
|
|
60
|
+
//response is a QuestionnaireResponse compatible object
|
|
61
|
+
submitData(Schemas.QuestionnaireResponse, response);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// using the `ConnectWelshareButton` is not mandatory. Use your own buttons if you feel like it.
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
{!isConnected ? (
|
|
68
|
+
<ConnectWelshareButton openWallet={openWallet}>
|
|
69
|
+
Connect to Welshare
|
|
70
|
+
</ConnectWelshareButton>
|
|
71
|
+
) : (
|
|
72
|
+
<form>
|
|
73
|
+
{/* ... some form that collects your response data ... */}
|
|
74
|
+
<button onClick={() => handleSubmit(response)} disabled={isSubmitting}>
|
|
75
|
+
{isSubmitting ? 'Submitting...' : 'Submit Data'}
|
|
76
|
+
</button>
|
|
77
|
+
</form>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API
|
|
85
|
+
|
|
86
|
+
### supported callbacks
|
|
87
|
+
|
|
88
|
+
those are configured in the `useWelshare` options parameter and called back during interactions with the wallet dialog
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
callbacks: {
|
|
92
|
+
onUploaded?: (payload: SubmissionPayload<unknown>) => void;
|
|
93
|
+
onError?: (error: string) => void;
|
|
94
|
+
onSessionReady?: (sessionPubKey: string) => void;
|
|
95
|
+
onDialogClosing?: () => void;
|
|
96
|
+
onDialogReady?: () => void;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Security Notes
|
|
101
|
+
|
|
102
|
+
No part of this application deals with a "blockchain" directly (Nillion nodes are validated by a custom chain but that's not a fact relevant for end users' security in this scope).
|
|
103
|
+
|
|
104
|
+
The EVM addresses that control a user profile are (supposedly) never leaked to a third party.
|
|
105
|
+
|
|
106
|
+
The key derivation mechanism that creates new storage keys that users use to sign messages is not guaranteed to be 100% sound. At this moment it's used as a cryptographic authenticator, but the derivation mechanism will change in the future, rendering already existing keys obsolete. We're not guaranteeing that your key material stays trivially derivable.
|
|
107
|
+
|
|
108
|
+
Data is stored on [nilDB (by Nillion)](https://docs.nillion.com/build/private-storage/quickstart), a system that can enforces access control, encryption at rest and storage redundancy. While technically possible, the current library does not MPC-encrypt any information. The data is sent to nilDB by a _user client_ that's controlled by the user's own key material. Welshare only delegates NUCs (access rights) to the users. Right now the welshare builder _can_ read any data users upload. This concept will eventually change - welshare's goal is to only make user originated information available inside trusted execution environments.
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
This package is built using:
|
|
113
|
+
|
|
114
|
+
- TypeScript
|
|
115
|
+
- Tshy for build management
|
|
116
|
+
- Vitest for testing
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT. See the [LICENSE](LICENSE) file for details.
|
|
121
|
+
|
|
122
|
+
## Contact
|
|
123
|
+
|
|
124
|
+
Get in touch on Telegram. Check https://welshare.health
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-button.d.ts","sourceRoot":"","sources":["../../../src/components/connect-button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAO,MAAM,qBAAqB,UAAW;IAC3C,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,4CAgFA,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const ConnectWelshareButton = (props) => {
|
|
3
|
+
// Self-contained styles that won't conflict with external applications
|
|
4
|
+
const buttonStyles = {
|
|
5
|
+
// Reset any inherited styles
|
|
6
|
+
all: 'unset',
|
|
7
|
+
boxSizing: 'border-box',
|
|
8
|
+
// Layout
|
|
9
|
+
display: 'inline-flex',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
justifyContent: 'center',
|
|
12
|
+
width: '100%',
|
|
13
|
+
minHeight: '44px',
|
|
14
|
+
padding: '12px 24px',
|
|
15
|
+
// Typography
|
|
16
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
17
|
+
fontSize: '16px',
|
|
18
|
+
fontWeight: '600',
|
|
19
|
+
lineHeight: '1.5',
|
|
20
|
+
textAlign: 'center',
|
|
21
|
+
textDecoration: 'none',
|
|
22
|
+
whiteSpace: 'nowrap',
|
|
23
|
+
// Visual styling
|
|
24
|
+
backgroundColor: '#0198ff',
|
|
25
|
+
background: 'linear-gradient(135deg, #0198ff 0%, #16ffef 100%)',
|
|
26
|
+
color: '#ffffff',
|
|
27
|
+
border: 'none',
|
|
28
|
+
borderRadius: '8px',
|
|
29
|
+
cursor: 'pointer',
|
|
30
|
+
transition: 'all 0.2s ease-in-out',
|
|
31
|
+
// Accessibility
|
|
32
|
+
userSelect: 'none',
|
|
33
|
+
WebkitUserSelect: 'none',
|
|
34
|
+
MozUserSelect: 'none',
|
|
35
|
+
// Focus states
|
|
36
|
+
outline: 'none',
|
|
37
|
+
};
|
|
38
|
+
// Handle hover and focus states since inline styles don't support pseudo-selectors
|
|
39
|
+
const handleMouseEnter = (e) => {
|
|
40
|
+
e.currentTarget.style.transform = 'translateY(-1px)';
|
|
41
|
+
e.currentTarget.style.boxShadow = '0 4px 12px rgba(1, 152, 255, 0.3)';
|
|
42
|
+
};
|
|
43
|
+
const handleMouseLeave = (e) => {
|
|
44
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
45
|
+
e.currentTarget.style.boxShadow = '0 2px 6px rgba(1, 152, 255, 0.2)';
|
|
46
|
+
};
|
|
47
|
+
const handleMouseDown = (e) => {
|
|
48
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
49
|
+
e.currentTarget.style.boxShadow = '0 2px 6px rgba(1, 152, 255, 0.2)';
|
|
50
|
+
};
|
|
51
|
+
const handleFocus = (e) => {
|
|
52
|
+
e.currentTarget.style.boxShadow = '0 0 0 3px rgba(1, 152, 255, 0.3)';
|
|
53
|
+
};
|
|
54
|
+
const handleBlur = (e) => {
|
|
55
|
+
e.currentTarget.style.boxShadow = '0 2px 6px rgba(1, 152, 255, 0.2)';
|
|
56
|
+
};
|
|
57
|
+
return (_jsx("button", { onClick: props.openWallet, style: buttonStyles, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: handleMouseDown, onFocus: handleFocus, onBlur: handleBlur, type: "button", children: props.children || "Connect Welshare Profile" }));
|
|
58
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SubmissionPayload, SubmissionSchemaId, WelshareConnectionOptions } from "@/types.js";
|
|
2
|
+
export declare const useWelshare: (props: WelshareConnectionOptions) => {
|
|
3
|
+
isConnected: boolean;
|
|
4
|
+
storageKey: string | undefined;
|
|
5
|
+
openWallet: () => void;
|
|
6
|
+
isDialogOpen: boolean;
|
|
7
|
+
submitData: <T>(schemaId: SubmissionSchemaId, submission: SubmissionPayload<T>) => void;
|
|
8
|
+
isSubmitting: boolean;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=use-welshare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-welshare.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-welshare.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAGpB,eAAO,MAAM,WAAW,UAAW,yBAAyB;;;;;iBAkFtC,CAAC,YACT,kBAAkB,cAChB,iBAAiB,CAAC,CAAC,CAAC;;CAuDnC,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
export const useWelshare = (props) => {
|
|
3
|
+
const [storageKey, setStorageKey] = useState();
|
|
4
|
+
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
5
|
+
const [dialogWindow, setDialogWindow] = useState(null);
|
|
6
|
+
const [messageIdCounter, setMessageIdCounter] = useState(0);
|
|
7
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
8
|
+
const options = {
|
|
9
|
+
environment: "development",
|
|
10
|
+
apiBaseUrl: "https://wallet.welshare.health",
|
|
11
|
+
...props,
|
|
12
|
+
};
|
|
13
|
+
const WELSHARE_WALLET_URL = `${options.apiBaseUrl}/wallet-external`;
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const handleMessage = (event) => {
|
|
16
|
+
// Verify origin for security
|
|
17
|
+
if (event.origin !== new URL(WELSHARE_WALLET_URL).origin) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const message = event.data;
|
|
21
|
+
let errorMessage = "";
|
|
22
|
+
switch (message.type) {
|
|
23
|
+
case "ERROR":
|
|
24
|
+
errorMessage = message.payload.error || "An unknown error occurred";
|
|
25
|
+
console.error("Welshare Wallet sent an error:", errorMessage);
|
|
26
|
+
setIsSubmitting(false);
|
|
27
|
+
options.callbacks.onError?.(errorMessage);
|
|
28
|
+
break;
|
|
29
|
+
case "DIALOG_READY":
|
|
30
|
+
setIsDialogOpen(true);
|
|
31
|
+
console.debug("Welshare Wallet Dialog is ready");
|
|
32
|
+
break;
|
|
33
|
+
case "SESSION_READY":
|
|
34
|
+
if (!message.payload.sessionPublicKey) {
|
|
35
|
+
errorMessage = "No session public key found";
|
|
36
|
+
console.error("Welshare Wallet sent a session without a key:", message.payload);
|
|
37
|
+
setStorageKey(undefined);
|
|
38
|
+
options.callbacks.onError?.(errorMessage);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
console.debug("Welshare Profile Session ready", message.payload);
|
|
42
|
+
setStorageKey(message.payload.sessionPublicKey);
|
|
43
|
+
options.callbacks.onSessionReady?.(message.payload.sessionPublicKey);
|
|
44
|
+
break;
|
|
45
|
+
case "DIALOG_CLOSING":
|
|
46
|
+
console.debug("Welshare Wallet Dialog is closing");
|
|
47
|
+
setStorageKey(undefined);
|
|
48
|
+
setIsDialogOpen(false);
|
|
49
|
+
options.callbacks.onDialogClosing?.();
|
|
50
|
+
break;
|
|
51
|
+
case "DATA_UPLOADED":
|
|
52
|
+
console.debug("data uploaded", message.payload);
|
|
53
|
+
setIsSubmitting(false);
|
|
54
|
+
options.callbacks.onUploaded?.(message.payload);
|
|
55
|
+
break;
|
|
56
|
+
default:
|
|
57
|
+
console.log("Received unexpected message from Welshare Wallet:", message);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
window.addEventListener("message", handleMessage);
|
|
61
|
+
return () => {
|
|
62
|
+
window.removeEventListener("message", handleMessage);
|
|
63
|
+
};
|
|
64
|
+
}, [WELSHARE_WALLET_URL, options.callbacks]);
|
|
65
|
+
/**
|
|
66
|
+
* @param schemaType a welshare schema type uid
|
|
67
|
+
* @param submission your submission that validates against the schema type
|
|
68
|
+
*/
|
|
69
|
+
const submitData = (schemaId, submission) => {
|
|
70
|
+
if (!dialogWindow) {
|
|
71
|
+
throw new Error("Dialog window not open");
|
|
72
|
+
}
|
|
73
|
+
const submissionPayload = {
|
|
74
|
+
applicationId: options.applicationId,
|
|
75
|
+
schemaId,
|
|
76
|
+
timestamp: new Date(),
|
|
77
|
+
submission,
|
|
78
|
+
};
|
|
79
|
+
//todo: before submitting data, consider verifying it locally here;
|
|
80
|
+
// 1. request the actual schema using a welshare api
|
|
81
|
+
// 2. create a json schema validator
|
|
82
|
+
// 3. run payload against that validator
|
|
83
|
+
// 4. submit
|
|
84
|
+
const message = {
|
|
85
|
+
type: "SUBMIT_DATA",
|
|
86
|
+
payload: submissionPayload,
|
|
87
|
+
id: String(messageIdCounter),
|
|
88
|
+
};
|
|
89
|
+
dialogWindow.postMessage(message, WELSHARE_WALLET_URL);
|
|
90
|
+
setIsSubmitting(true);
|
|
91
|
+
setMessageIdCounter((prev) => prev + 1);
|
|
92
|
+
};
|
|
93
|
+
const openWallet = () => {
|
|
94
|
+
const width = 800;
|
|
95
|
+
const height = 600;
|
|
96
|
+
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
97
|
+
const top = window.screenY + (window.outerHeight - height) / 2;
|
|
98
|
+
const newWindow = window.open(WELSHARE_WALLET_URL, "Welshare Wallet", `width=${width},height=${height},left=${left},top=${top}`);
|
|
99
|
+
if (newWindow) {
|
|
100
|
+
setDialogWindow(newWindow);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
isConnected: !!storageKey,
|
|
105
|
+
storageKey,
|
|
106
|
+
openWallet,
|
|
107
|
+
isDialogOpen,
|
|
108
|
+
submitData,
|
|
109
|
+
isSubmitting,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,OAAO,EACL,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAGjC,eAAO,MAAM,OAAO;;;CAGnB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//todo: this is not tree shaken and leaks nillion dependencies transitively. Consider pulling it up
|
|
2
|
+
//import { QuestionnaireResponseSchema, ReflexSubmissionSchema } from "@welshare/sdk";
|
|
3
|
+
export { ConnectWelshareButton } from "./components/connect-button.js";
|
|
4
|
+
// ---- hooks ----
|
|
5
|
+
export { useWelshare } from "./hooks/use-welshare.js";
|
|
6
|
+
//todo: import them from the SDK or a dedicated SDK constants export
|
|
7
|
+
export const Schemas = {
|
|
8
|
+
QuestionnaireResponse: "b14b538f-7de3-4767-ad77-464d755d78bd", //QuestionnaireResponseSchema.schemaUid,
|
|
9
|
+
ReflexSubmission: "f5cf2d8a-1f78-4f21-b4bd-082e983b830c" //ReflexSubmissionSchema.schemaUid,
|
|
10
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface DialogMessage {
|
|
2
|
+
type: string;
|
|
3
|
+
payload?: any;
|
|
4
|
+
id?: string;
|
|
5
|
+
}
|
|
6
|
+
export type WelshareEnvironment = "development" | "production";
|
|
7
|
+
/**
|
|
8
|
+
* a welshare schema type uid
|
|
9
|
+
*/
|
|
10
|
+
export type SubmissionSchemaId = string;
|
|
11
|
+
export interface SubmissionPayload<T> {
|
|
12
|
+
applicationId: string;
|
|
13
|
+
timestamp: Date;
|
|
14
|
+
schemaId: SubmissionSchemaId;
|
|
15
|
+
submission: T;
|
|
16
|
+
}
|
|
17
|
+
export interface DataSubmissionDialogMessage extends DialogMessage {
|
|
18
|
+
payload: SubmissionPayload<unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface WelshareConnectionOptions {
|
|
21
|
+
applicationId: string;
|
|
22
|
+
apiBaseUrl?: string;
|
|
23
|
+
environment?: WelshareEnvironment;
|
|
24
|
+
callbacks: {
|
|
25
|
+
onUploaded?: (payload: SubmissionPayload<unknown>) => void;
|
|
26
|
+
onError?: (error: string) => void;
|
|
27
|
+
onSessionReady?: (sessionPubKey: string) => void;
|
|
28
|
+
onDialogClosing?: () => void;
|
|
29
|
+
onDialogReady?: () => void;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,YAAY,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAEvC,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,CAAC,CAAC;CACf;AAED,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IAChE,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,MAAM,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,EAAE;QACT,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;QAC3D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,cAAc,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;QACjD,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;KAC5B,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Source files
|
|
2
|
+
src/
|
|
3
|
+
tsconfig.json
|
|
4
|
+
tsconfig.lint.json
|
|
5
|
+
tshy.config.ts
|
|
6
|
+
vitest.config.ts
|
|
7
|
+
|
|
8
|
+
# Development files
|
|
9
|
+
.github/
|
|
10
|
+
.vscode/
|
|
11
|
+
*.log
|
|
12
|
+
*.tsbuildinfo
|
|
13
|
+
|
|
14
|
+
# Test files
|
|
15
|
+
__tests__/
|
|
16
|
+
*.test.*
|
|
17
|
+
*.spec.*
|
|
18
|
+
|
|
19
|
+
# Build artifacts
|
|
20
|
+
.tshy-build/
|
|
21
|
+
coverage/
|
|
22
|
+
.vitest/
|
|
23
|
+
|
|
24
|
+
# Development dependencies
|
|
25
|
+
node_modules/
|
|
26
|
+
|
|
27
|
+
# IDE files
|
|
28
|
+
.idea/
|
|
29
|
+
*.swp
|
|
30
|
+
*.swo
|
|
31
|
+
|
|
32
|
+
# OS files
|
|
33
|
+
.DS_Store
|
|
34
|
+
Thumbs.db
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./build.json",
|
|
3
|
+
"include": [
|
|
4
|
+
"../src/**/*.ts",
|
|
5
|
+
"../src/**/*.mts",
|
|
6
|
+
"../src/**/*.tsx",
|
|
7
|
+
"../src/**/*.json"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"../src/**/__tests__/**",
|
|
11
|
+
"../src/package.json"
|
|
12
|
+
],
|
|
13
|
+
"compilerOptions": {
|
|
14
|
+
"outDir": "../.tshy-build/esm"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright © 2025 Welshare Health UG (haftungsbeschränkt) 2025
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @welshare/react
|
|
2
|
+
|
|
3
|
+
### Disclaimer, notes on maturity
|
|
4
|
+
|
|
5
|
+
This library is in Alpha / demo state at this moment. We're using it to review the security aspects while data is in transfer and in rest. There's absolutely no guarantee or warrant that at this point any data is safe. All data can be lost at any time - even though we're using resources that puts decentralization and resilience values to the front. Be **very** careful if you're integrating this into user facing code. Welshare Health wallets are controlled by cryptographic material which _can_ be stored in non custodial / MPC environments (Privy). While that's considered very safe, we can't guarantee at this point that we've already got each aspect of inter application communication or key derivation features right, so don't connect wallets that store significant value with the welshare wallet yet.
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
This is a React library that helps integrating with Welshare's sovereign data sharing platform. This package provides React hooks and components to connect applications with Welshare's wallet for secure data submission.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @welshare/react
|
|
15
|
+
# or
|
|
16
|
+
yarn add @welshare/react
|
|
17
|
+
# or
|
|
18
|
+
pnpm add @welshare/react
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Peer Dependencies
|
|
22
|
+
|
|
23
|
+
This package requires React 19+ as a peer dependency.
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
|
|
27
|
+
You need to register an app identifier using the Welshare Wallet frontend first: https://wallet.welshare.app/application. We're referring to this as `your-application-id` from here on.
|
|
28
|
+
|
|
29
|
+
If you want to submit questionnaire data, your application must first register a new questionnaire definition. You can also reuse an existing questionnaire id to let users contribute responses to another app's questionaire, but that's not highly encouraged at this point.
|
|
30
|
+
|
|
31
|
+
## Data Submissions
|
|
32
|
+
|
|
33
|
+
At the moment there are only two supported submission types: Fhir compatible QuestionnaireResponses and our custom "Reflex" app submissions. Both types are identified by schema uids that are accessible on the `Schemas` export.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
export const Schemas = {
|
|
37
|
+
QuestionnaireResponse: "b14b538f-7de3-4767-ad77-464d755d78bd"
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To submit questionnaires using custom frontends, you'll use the `useWelshare` hook to open a wallet dialog that lets your application talk to the user's connected wallets (using derived storage keys). All communication with the Welshare infrastructure happens inside that browser window.
|
|
42
|
+
|
|
43
|
+
## Code Sample
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { ConnectWelshareButton, Schemas, useWelshare } from "@welshare/react";
|
|
47
|
+
|
|
48
|
+
export function QuestionnaireForm() {
|
|
49
|
+
const { isConnected, openWallet, submitData } = useWelshare({
|
|
50
|
+
applicationId: <your-application-id>,
|
|
51
|
+
environment: "development", //optional, at the moment the environment is always development
|
|
52
|
+
callbacks: {
|
|
53
|
+
onUploaded: (payload) => console.log('Data uploaded:', payload),
|
|
54
|
+
onError: (error) => console.error('Error:', error),
|
|
55
|
+
onSessionReady: (storageKey) => console.log('Session ready:', storageKey),
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const handleSubmit = () => {
|
|
60
|
+
//response is a QuestionnaireResponse compatible object
|
|
61
|
+
submitData(Schemas.QuestionnaireResponse, response);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// using the `ConnectWelshareButton` is not mandatory. Use your own buttons if you feel like it.
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
{!isConnected ? (
|
|
68
|
+
<ConnectWelshareButton openWallet={openWallet}>
|
|
69
|
+
Connect to Welshare
|
|
70
|
+
</ConnectWelshareButton>
|
|
71
|
+
) : (
|
|
72
|
+
<form>
|
|
73
|
+
{/* ... some form that collects your response data ... */}
|
|
74
|
+
<button onClick={() => handleSubmit(response)} disabled={isSubmitting}>
|
|
75
|
+
{isSubmitting ? 'Submitting...' : 'Submit Data'}
|
|
76
|
+
</button>
|
|
77
|
+
</form>
|
|
78
|
+
)}
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API
|
|
85
|
+
|
|
86
|
+
### supported callbacks
|
|
87
|
+
|
|
88
|
+
those are configured in the `useWelshare` options parameter and called back during interactions with the wallet dialog
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
callbacks: {
|
|
92
|
+
onUploaded?: (payload: SubmissionPayload<unknown>) => void;
|
|
93
|
+
onError?: (error: string) => void;
|
|
94
|
+
onSessionReady?: (sessionPubKey: string) => void;
|
|
95
|
+
onDialogClosing?: () => void;
|
|
96
|
+
onDialogReady?: () => void;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Security Notes
|
|
101
|
+
|
|
102
|
+
No part of this application deals with a "blockchain" directly (Nillion nodes are validated by a custom chain but that's not a fact relevant for end users' security in this scope).
|
|
103
|
+
|
|
104
|
+
The EVM addresses that control a user profile are (supposedly) never leaked to a third party.
|
|
105
|
+
|
|
106
|
+
The key derivation mechanism that creates new storage keys that users use to sign messages is not guaranteed to be 100% sound. At this moment it's used as a cryptographic authenticator, but the derivation mechanism will change in the future, rendering already existing keys obsolete. We're not guaranteeing that your key material stays trivially derivable.
|
|
107
|
+
|
|
108
|
+
Data is stored on [nilDB (by Nillion)](https://docs.nillion.com/build/private-storage/quickstart), a system that can enforces access control, encryption at rest and storage redundancy. While technically possible, the current library does not MPC-encrypt any information. The data is sent to nilDB by a _user client_ that's controlled by the user's own key material. Welshare only delegates NUCs (access rights) to the users. Right now the welshare builder _can_ read any data users upload. This concept will eventually change - welshare's goal is to only make user originated information available inside trusted execution environments.
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
This package is built using:
|
|
113
|
+
|
|
114
|
+
- TypeScript
|
|
115
|
+
- Tshy for build management
|
|
116
|
+
- Vitest for testing
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT. See the [LICENSE](LICENSE) file for details.
|
|
121
|
+
|
|
122
|
+
## Contact
|
|
123
|
+
|
|
124
|
+
Get in touch on Telegram. Check https://welshare.health
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-button.d.ts","sourceRoot":"","sources":["../../../src/components/connect-button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAO,MAAM,qBAAqB,UAAW;IAC3C,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,4CAgFA,CAAC"}
|