Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

14 implement mediation coordination workflow #18

Merged
merged 14 commits into from
Feb 4, 2025
6 changes: 6 additions & 0 deletions libs/did-resolver-lib/src/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { DIDDoc, DIDResolver, Service, VerificationMethod } from 'didcomm';
import base64url from 'base64url';
import { Buffer } from 'buffer';

// Polyfill Buffer for environments like the browser
if (!globalThis.Buffer) {
globalThis.Buffer = Buffer;
}

type Purpose =
| 'Assertion'
Expand Down
4 changes: 3 additions & 1 deletion libs/message-handler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"format:check": "prettier --check .",
"preview": "vite preview"
},
"dependencies": {},
"dependencies": {
"uuidv4": "^6.2.13"
},
"devDependencies": {
"@babel/preset-typescript": "^7.25.9",
"@eslint/js": "^9.11.1",
Expand Down
6 changes: 6 additions & 0 deletions libs/message-handler/services/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,11 @@
"typescript": "~5.6.2",
"typescript-eslint": "^8.18.2",
"vite": "^6.0.5"
},
"dependencies": {
"didcomm": "^0.4.1",
"message-handler": "^0.0.17",
"uuid": "^11.0.5",
"uuidv4": "^6.2.13"
}
}
7 changes: 6 additions & 1 deletion libs/message-handler/services/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@ import MediatorApp from './data-collection';
import MediatorCoordination from './components/MediatorCoordination';
import PickupComponent from './components/PickupRequest';
import ForwardComponent from './components/ForwardRequest';
import QueryComponent from './components/Mediation-components/Query';
import RequestComponent from './components/Mediation-components/Request';

const App: React.FC = () => {
return (
<Router>
<Routes>
<Route path="/" element={<MediatorApp />} />
<Route path="/coordination" element={<MediatorCoordination />} />
<Route path="/coordination/*" element={<MediatorCoordination />} />
<Route path="/pickup" element={<PickupComponent />} />
<Route path="/forward" element={<ForwardComponent />} />
<Route path="/query" element={<QueryComponent />} />
<Route path="/mediateRequest" element={<RequestComponent />} />
<Route path="*" element={<div>404 - Page Not Found</div>} />
</Routes>
</Router>
);
Expand Down
137 changes: 129 additions & 8 deletions libs/message-handler/services/src/components/ForwardRequest.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,134 @@
// ForwardComponent.tsx
import React from 'react';
import React, { useState } from 'react';
import {
TextField,
Button,
CircularProgress,
Box,
Typography,
} from '@mui/material';
import { forward_msg } from './../../../src/protocols/forward-client';

const ForwardMessageUI = () => {
const [mediator_did, setMediatorDID] = useState('');
const [message, setMessage] = useState('');
const [recipient_did, setRecipientDid] = useState('');
const [response, setResponse] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError(null);
setResponse(null);

try {
const result = await forward_msg(
[mediator_did],
[recipient_did],
message,
);
setResponse(result);
} catch (err) {
setError(
`Error: ${err instanceof Error ? err.message : 'Unknown error'}`,
);
} finally {
setLoading(false);
}
};

const ForwardComponent: React.FC = () => {
return (
<div>
<h1>Forward Section</h1>
<p>This is the page where forwarding happens.</p>
</div>
<Box sx={{ maxWidth: 400, margin: '0 auto', padding: 2 }}>
<Typography variant="h5" gutterBottom>
Forward DIDComm Message
</Typography>

<Typography variant="body2" gutterBottom>
Enter the recipient's DID and your message below.
</Typography>

<form onSubmit={handleSubmit}>
<TextField
label="Mediator DID"
fullWidth
value={mediator_did}
onChange={(e) => setMediatorDID(e.target.value)}
margin="normal"
required
/>

<TextField
label="Recipient DID"
fullWidth
value={recipient_did}
onChange={(e) => setRecipientDid(e.target.value)}
margin="normal"
required
/>

<TextField
label="Message"
fullWidth
value={message}
onChange={(e) => setMessage(e.target.value)}
margin="normal"
multiline
rows={4}
required
/>

<Button
type="submit"
variant="contained"
fullWidth
disabled={loading}
sx={{ marginTop: 2 }}
>
{loading ? 'Sending...' : 'Send Message'}
</Button>
</form>

{loading && (
<Box sx={{ display: 'flex', justifyContent: 'center', marginTop: 2 }}>
<CircularProgress />
</Box>
)}

{response && (
<Box sx={{ marginTop: 2 }}>
<Typography variant="h6">Response:</Typography>
<Typography
sx={{
backgroundColor: '#e8f5e9',
padding: '10px',
borderRadius: '4px',
border: '1px solid #c8e6c9',
color: '#388e3c',
}}
>
{response}
</Typography>
</Box>
)}

{error && (
<Box sx={{ marginTop: 2 }}>
<Typography
sx={{
backgroundColor: '#ffebee',
padding: '10px',
borderRadius: '4px',
border: '1px solid #ffcdd2',
color: '#d32f2f',
}}
>
{error}
</Typography>
</Box>
)}
</Box>
);
};

export default ForwardComponent;
export default ForwardMessageUI;
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { useState } from 'react';
import {
TextField,
Button,
CircularProgress,
Box,
Typography,
} from '@mui/material';
import { keylistQuery } from '../../../../src/mediation-coordination';
import { IMessage, Message } from 'didcomm';

const KeylistQueryUI = () => {
const [recipientDid, setRecipientDid] = useState('');
const [mediatorDid, setMediatorDid] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [result, setResult] = useState<IMessage | null>(null);
const [error, setError] = useState<string | null>(null);

const handleKeylistQuery = async () => {
setIsLoading(true);
setResult(null);
setError(null);

try {
const response = await keylistQuery([mediatorDid]);
const message: Message = response as Message;
const result: IMessage = message.as_value();
setResult(result);
} catch (err) {
setError(
`Error: ${err instanceof Error ? err.message : 'Unknown error'}`,
);
} finally {
setIsLoading(false);
}
};

return (
<Box sx={{ maxWidth: 400, margin: '0 auto', padding: 2 }}>
<Typography variant="h5" gutterBottom>
Keylist Query
</Typography>

<TextField
label="Mediator DID"
fullWidth
value={mediatorDid}
onChange={(e) => setMediatorDid(e.target.value)}
margin="normal"
/>

<TextField
label="Recipient DID"
fullWidth
value={recipientDid}
onChange={(e) => setRecipientDid(e.target.value)}
margin="normal"
/>

<Button
variant="contained"
fullWidth
onClick={handleKeylistQuery}
disabled={isLoading}
sx={{ marginTop: 2 }}
>
{isLoading ? 'Querying...' : 'Execute Query'}
</Button>

{isLoading && (
<Box sx={{ display: 'flex', justifyContent: 'center', marginTop: 2 }}>
<CircularProgress />
</Box>
)}

{result && (
<Box sx={{ marginTop: 2 }}>
<Typography variant="h6">Query Result:</Typography>
<pre style={{ background: '#f4f4f4', padding: '10px' }}>
{JSON.stringify(result, null, 2)}
</pre>
</Box>
)}

{error && (
<Box sx={{ marginTop: 2, color: 'red' }}>
<Typography variant="body2">{error}</Typography>
</Box>
)}
</Box>
);
};

export default KeylistQueryUI;
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState } from 'react';
import './request.css';
import mediationCoordination from '../../../../src/mediation-coordination';

const MediateRequestUI: React.FC = () => {
const [mediatorDid, setMediatorDid] = useState('');
const [recipientDid, setRecipientDid] = useState('');
const [loading, setLoading] = useState(false);
const [response, setResponse] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);

const handleMediateRequest = async () => {
setLoading(true);
setResponse(null);
setError(null);

try {
const response = await mediationCoordination(mediatorDid);
if (response) {
setResponse(JSON.stringify(response.as_value()));
} else {
setResponse(null);
}
} catch (err) {
setError(
`Error: ${err instanceof Error ? err.message : 'Unknown error'}`,
);
} finally {
setLoading(false);
}
};

return (
<div className="mediate-request-ui">
<h1>Mediation Request</h1>
<form
onSubmit={(e) => {
e.preventDefault();
handleMediateRequest();
}}
>
<div className="form-group">
<label htmlFor="mediatorDid">Mediator DID:</label>
<input
type="text"
id="mediatorDid"
value={mediatorDid}
onChange={(e) => setMediatorDid(e.target.value)}
required
/>
</div>
<div className="form-group">
<label htmlFor="recipientDid">Recipient DID:</label>
<input
type="text"
id="recipientDid"
value={recipientDid}
onChange={(e) => setRecipientDid(e.target.value)}
required
/>
</div>
<button type="submit" disabled={loading}>
{loading ? 'Processing...' : 'Send Mediation Request'}
</button>
</form>
{error && <p className="error">Error: {error}</p>}
{response && (
<div className="response">
<h2>Response:</h2>
<pre>{response}</pre>
</div>
)}
</div>
);
};

export default MediateRequestUI;
Loading