@iexec/web3mail 1.5.0 → 1.6.0-nightly-b2a0e93
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/dist/config/config.js +0 -1
- package/dist/config/config.js.map +1 -1
- package/dist/utils/subgraphQuery.js +6 -2
- package/dist/utils/subgraphQuery.js.map +1 -1
- package/dist/web3mail/IExecWeb3mail.d.ts +2 -1
- package/dist/web3mail/IExecWeb3mail.js +15 -0
- package/dist/web3mail/IExecWeb3mail.js.map +1 -1
- package/dist/web3mail/fetchMyContacts.d.ts +1 -1
- package/dist/web3mail/fetchMyContacts.js +2 -1
- package/dist/web3mail/fetchMyContacts.js.map +1 -1
- package/dist/web3mail/fetchUserContacts.d.ts +1 -1
- package/dist/web3mail/fetchUserContacts.js +20 -3
- package/dist/web3mail/fetchUserContacts.js.map +1 -1
- package/dist/web3mail/internalTypes.d.ts +4 -0
- package/dist/web3mail/sendEmail.d.ts +2 -2
- package/dist/web3mail/sendEmail.js +135 -187
- package/dist/web3mail/sendEmail.js.map +1 -1
- package/dist/web3mail/types.d.ts +39 -3
- package/package.json +3 -3
- package/src/config/config.ts +0 -1
- package/src/utils/subgraphQuery.ts +18 -14
- package/src/web3mail/IExecWeb3mail.ts +22 -2
- package/src/web3mail/fetchMyContacts.ts +2 -0
- package/src/web3mail/fetchUserContacts.ts +30 -15
- package/src/web3mail/internalTypes.ts +3 -0
- package/src/web3mail/sendEmail.ts +149 -219
- package/src/web3mail/types.ts +42 -3
|
@@ -1,161 +1,53 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_CONTENT_TYPE, MAX_DESIRED_APP_ORDER_PRICE, MAX_DESIRED_DATA_ORDER_PRICE, MAX_DESIRED_WORKERPOOL_ORDER_PRICE, } from '../config/config.js';
|
|
3
3
|
import { handleIfProtocolError, WorkflowError } from '../utils/errors.js';
|
|
4
|
-
import { generateSecureUniqueId } from '../utils/generateUniqueId.js';
|
|
5
4
|
import * as ipfs from '../utils/ipfs-service.js';
|
|
6
5
|
import { checkProtectedDataValidity } from '../utils/subgraphQuery.js';
|
|
7
|
-
import { addressOrEnsSchema,
|
|
8
|
-
|
|
9
|
-
export const sendEmail = async ({ graphQLClient = throwIfMissing(), iexec = throwIfMissing(), workerpoolAddressOrEns, dappAddressOrENS, dappWhitelistAddress, ipfsNode, ipfsGateway, emailSubject, emailContent, contentType = DEFAULT_CONTENT_TYPE, label, dataMaxPrice = MAX_DESIRED_DATA_ORDER_PRICE, appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE, workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE, senderName, protectedData, useVoucher = false, }) => {
|
|
10
|
-
const vDatasetAddress = addressOrEnsSchema()
|
|
11
|
-
.required()
|
|
12
|
-
.label('protectedData')
|
|
13
|
-
.validateSync(protectedData);
|
|
14
|
-
const vEmailSubject = emailSubjectSchema()
|
|
15
|
-
.required()
|
|
16
|
-
.label('emailSubject')
|
|
17
|
-
.validateSync(emailSubject);
|
|
18
|
-
const vEmailContent = emailContentSchema()
|
|
19
|
-
.required()
|
|
20
|
-
.label('emailContent')
|
|
21
|
-
.validateSync(emailContent);
|
|
22
|
-
const vContentType = contentTypeSchema()
|
|
23
|
-
.required()
|
|
24
|
-
.label('contentType')
|
|
25
|
-
.validateSync(contentType);
|
|
26
|
-
const vSenderName = senderNameSchema()
|
|
27
|
-
.label('senderName')
|
|
28
|
-
.validateSync(senderName);
|
|
29
|
-
const vLabel = labelSchema().label('label').validateSync(label);
|
|
30
|
-
const vWorkerpoolAddressOrEns = addressOrEnsSchema()
|
|
31
|
-
.required()
|
|
32
|
-
.label('WorkerpoolAddressOrEns')
|
|
33
|
-
.validateSync(workerpoolAddressOrEns);
|
|
34
|
-
const vDappAddressOrENS = addressOrEnsSchema()
|
|
35
|
-
.required()
|
|
36
|
-
.label('dappAddressOrENS')
|
|
37
|
-
.validateSync(dappAddressOrENS);
|
|
38
|
-
const vDappWhitelistAddress = addressSchema()
|
|
39
|
-
.required()
|
|
40
|
-
.label('dappWhitelistAddress')
|
|
41
|
-
.validateSync(dappWhitelistAddress);
|
|
42
|
-
const vDataMaxPrice = positiveNumberSchema()
|
|
43
|
-
.label('dataMaxPrice')
|
|
44
|
-
.validateSync(dataMaxPrice);
|
|
45
|
-
const vAppMaxPrice = positiveNumberSchema()
|
|
46
|
-
.label('appMaxPrice')
|
|
47
|
-
.validateSync(appMaxPrice);
|
|
48
|
-
const vWorkerpoolMaxPrice = positiveNumberSchema()
|
|
49
|
-
.label('workerpoolMaxPrice')
|
|
50
|
-
.validateSync(workerpoolMaxPrice);
|
|
51
|
-
const vUseVoucher = booleanSchema()
|
|
52
|
-
.label('useVoucher')
|
|
53
|
-
.validateSync(useVoucher);
|
|
54
|
-
// Check protected data schema through subgraph
|
|
55
|
-
const isValidProtectedData = await checkProtectedDataValidity(graphQLClient, vDatasetAddress);
|
|
56
|
-
if (!isValidProtectedData) {
|
|
57
|
-
throw new Error('This protected data does not contain "email:string" in its schema.');
|
|
58
|
-
}
|
|
59
|
-
const requesterAddress = await iexec.wallet.getAddress();
|
|
60
|
-
let userVoucher;
|
|
61
|
-
if (vUseVoucher) {
|
|
62
|
-
try {
|
|
63
|
-
userVoucher = await iexec.voucher.showUserVoucher(requesterAddress);
|
|
64
|
-
checkUserVoucher({ userVoucher });
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
if (err?.message?.startsWith('No Voucher found for address')) {
|
|
68
|
-
throw new Error('Oops, it seems your wallet is not associated with any voucher. Check on https://builder.iex.ec/');
|
|
69
|
-
}
|
|
70
|
-
throw err;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
6
|
+
import { addressOrEnsSchema, booleanSchema, contentTypeSchema, emailContentSchema, emailSubjectSchema, labelSchema, positiveNumberSchema, senderNameSchema, throwIfMissing, } from '../utils/validators.js';
|
|
7
|
+
export const sendEmail = async ({ graphQLClient = throwIfMissing(), iexec = throwIfMissing(), dataProtector = throwIfMissing(), workerpoolAddressOrEns = throwIfMissing(), dappAddressOrENS, ipfsNode, ipfsGateway, emailSubject, emailContent, contentType = DEFAULT_CONTENT_TYPE, label, dataMaxPrice = MAX_DESIRED_DATA_ORDER_PRICE, appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE, workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE, senderName, protectedData, grantedAccess, maxProtectedDataPerTask, useVoucher = false, }) => {
|
|
73
8
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
dataset: vDatasetAddress,
|
|
117
|
-
requester: requesterAddress, // public orders + user specific orders
|
|
118
|
-
isRequesterStrict: useVoucher, // If voucher, we only want user specific orders
|
|
119
|
-
minTag: ['tee', 'scone'],
|
|
120
|
-
maxTag: ['tee', 'scone'],
|
|
121
|
-
category: 0,
|
|
122
|
-
}),
|
|
123
|
-
// for app whitelist
|
|
124
|
-
iexec.orderbook.fetchWorkerpoolOrderbook({
|
|
125
|
-
workerpool: workerpoolAddressOrEns,
|
|
126
|
-
app: vDappWhitelistAddress,
|
|
127
|
-
dataset: vDatasetAddress,
|
|
128
|
-
requester: requesterAddress, // public orders + user specific orders
|
|
129
|
-
isRequesterStrict: useVoucher, // If voucher, we only want user specific orders
|
|
130
|
-
minTag: ['tee', 'scone'],
|
|
131
|
-
maxTag: ['tee', 'scone'],
|
|
132
|
-
category: 0,
|
|
133
|
-
}),
|
|
134
|
-
]).then(([workerpoolOrderbookForApp, workerpoolOrderbookForAppWhitelist]) => {
|
|
135
|
-
const desiredPriceWorkerpoolOrder = filterWorkerpoolOrders({
|
|
136
|
-
workerpoolOrders: [
|
|
137
|
-
...workerpoolOrderbookForApp.orders,
|
|
138
|
-
...workerpoolOrderbookForAppWhitelist.orders,
|
|
139
|
-
],
|
|
140
|
-
workerpoolMaxPrice: vWorkerpoolMaxPrice,
|
|
141
|
-
useVoucher: vUseVoucher,
|
|
142
|
-
userVoucher,
|
|
143
|
-
});
|
|
144
|
-
if (!desiredPriceWorkerpoolOrder) {
|
|
145
|
-
throw new Error('No Workerpool order found for the desired price');
|
|
146
|
-
}
|
|
147
|
-
return desiredPriceWorkerpoolOrder;
|
|
148
|
-
}),
|
|
149
|
-
]);
|
|
150
|
-
if (!workerpoolorder) {
|
|
151
|
-
throw new Error('No Workerpool order found for the desired price');
|
|
152
|
-
}
|
|
153
|
-
const datasetorder = datasetorderForApp || datasetorderForWhitelist;
|
|
154
|
-
if (!datasetorder) {
|
|
155
|
-
throw new Error('No Dataset order found for the desired price');
|
|
156
|
-
}
|
|
157
|
-
// Push requester secrets
|
|
158
|
-
const requesterSecretId = generateSecureUniqueId(16);
|
|
9
|
+
const vUseVoucher = booleanSchema()
|
|
10
|
+
.label('useVoucher')
|
|
11
|
+
.validateSync(useVoucher);
|
|
12
|
+
const vWorkerpoolAddressOrEns = addressOrEnsSchema()
|
|
13
|
+
.required()
|
|
14
|
+
.label('WorkerpoolAddressOrEns')
|
|
15
|
+
.validateSync(workerpoolAddressOrEns);
|
|
16
|
+
const vSenderName = senderNameSchema()
|
|
17
|
+
.label('senderName')
|
|
18
|
+
.validateSync(senderName);
|
|
19
|
+
const vEmailSubject = emailSubjectSchema()
|
|
20
|
+
.required()
|
|
21
|
+
.label('emailSubject')
|
|
22
|
+
.validateSync(emailSubject);
|
|
23
|
+
const vEmailContent = emailContentSchema()
|
|
24
|
+
.required()
|
|
25
|
+
.label('emailContent')
|
|
26
|
+
.validateSync(emailContent);
|
|
27
|
+
const vContentType = contentTypeSchema()
|
|
28
|
+
.required()
|
|
29
|
+
.label('contentType')
|
|
30
|
+
.validateSync(contentType);
|
|
31
|
+
const vLabel = labelSchema().label('label').validateSync(label);
|
|
32
|
+
const vDappAddressOrENS = addressOrEnsSchema()
|
|
33
|
+
.required()
|
|
34
|
+
.label('dappAddressOrENS')
|
|
35
|
+
.validateSync(dappAddressOrENS);
|
|
36
|
+
// TODO: remove this once we have a way to pass appWhitelist to processProtectedData function
|
|
37
|
+
// const vDappWhitelistAddress = addressSchema()
|
|
38
|
+
// .required()
|
|
39
|
+
// .label('dappWhitelistAddress')
|
|
40
|
+
// .validateSync(dappWhitelistAddress);
|
|
41
|
+
const vDataMaxPrice = positiveNumberSchema()
|
|
42
|
+
.label('dataMaxPrice')
|
|
43
|
+
.validateSync(dataMaxPrice);
|
|
44
|
+
const vAppMaxPrice = positiveNumberSchema()
|
|
45
|
+
.label('appMaxPrice')
|
|
46
|
+
.validateSync(appMaxPrice);
|
|
47
|
+
const vWorkerpoolMaxPrice = positiveNumberSchema()
|
|
48
|
+
.label('workerpoolMaxPrice')
|
|
49
|
+
.validateSync(workerpoolMaxPrice);
|
|
50
|
+
// Encrypt email content
|
|
159
51
|
const emailContentEncryptionKey = iexec.dataset.generateEncryptionKey();
|
|
160
52
|
const encryptedFile = await iexec.dataset
|
|
161
53
|
.encrypt(Buffer.from(vEmailContent, 'utf8'), emailContentEncryptionKey)
|
|
@@ -165,10 +57,11 @@ export const sendEmail = async ({ graphQLClient = throwIfMissing(), iexec = thro
|
|
|
165
57
|
errorCause: e,
|
|
166
58
|
});
|
|
167
59
|
});
|
|
60
|
+
// Push email message to IPFS
|
|
168
61
|
const cid = await ipfs
|
|
169
62
|
.add(encryptedFile, {
|
|
170
|
-
ipfsNode
|
|
171
|
-
ipfsGateway
|
|
63
|
+
ipfsNode,
|
|
64
|
+
ipfsGateway,
|
|
172
65
|
})
|
|
173
66
|
.catch((e) => {
|
|
174
67
|
throw new WorkflowError({
|
|
@@ -177,46 +70,101 @@ export const sendEmail = async ({ graphQLClient = throwIfMissing(), iexec = thro
|
|
|
177
70
|
});
|
|
178
71
|
});
|
|
179
72
|
const multiaddr = `/ipfs/${cid}`;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
73
|
+
// Prepare secrets for the requester
|
|
74
|
+
// Use a positive integer as secret ID (required by iexec)
|
|
75
|
+
// Using "1" as a fixed ID for the requester secret
|
|
76
|
+
const requesterSecretId = 1;
|
|
77
|
+
const secrets = {
|
|
78
|
+
[requesterSecretId]: JSON.stringify({
|
|
79
|
+
senderName: vSenderName,
|
|
80
|
+
emailSubject: vEmailSubject,
|
|
81
|
+
emailContentMultiAddr: multiaddr,
|
|
82
|
+
contentType: vContentType,
|
|
83
|
+
emailContentEncryptionKey,
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
// Bulk processing
|
|
87
|
+
if (grantedAccess) {
|
|
88
|
+
const vMaxProtectedDataPerTask = positiveNumberSchema()
|
|
89
|
+
.label('maxProtectedDataPerTask')
|
|
90
|
+
.validateSync(maxProtectedDataPerTask);
|
|
91
|
+
const bulkRequest = await dataProtector.prepareBulkRequest({
|
|
92
|
+
app: vDappAddressOrENS,
|
|
93
|
+
appMaxPrice: vAppMaxPrice,
|
|
94
|
+
workerpoolMaxPrice: vWorkerpoolMaxPrice,
|
|
95
|
+
workerpool: vWorkerpoolAddressOrEns,
|
|
96
|
+
args: vLabel,
|
|
97
|
+
inputFiles: [],
|
|
98
|
+
secrets,
|
|
99
|
+
bulkAccesses: grantedAccess,
|
|
100
|
+
maxProtectedDataPerTask: vMaxProtectedDataPerTask,
|
|
101
|
+
});
|
|
102
|
+
const processBulkRequestResponse = await dataProtector.processBulkRequest({
|
|
103
|
+
bulkRequest: bulkRequest.bulkRequest,
|
|
104
|
+
useVoucher: vUseVoucher,
|
|
105
|
+
workerpool: vWorkerpoolAddressOrEns,
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
tasks: processBulkRequestResponse.tasks.map((task) => ({
|
|
109
|
+
taskId: task.taskId,
|
|
110
|
+
dealId: task.dealId,
|
|
111
|
+
bulkIndex: task.bulkIndex,
|
|
112
|
+
})),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Single processing mode - protectedData is required
|
|
116
|
+
const vDatasetAddress = addressOrEnsSchema()
|
|
117
|
+
.required()
|
|
118
|
+
.label('protectedData')
|
|
119
|
+
.validateSync(protectedData);
|
|
120
|
+
// Check protected data validity through subgraph
|
|
121
|
+
const isValidProtectedData = await checkProtectedDataValidity(graphQLClient, vDatasetAddress);
|
|
122
|
+
if (!isValidProtectedData) {
|
|
123
|
+
throw new Error('This protected data does not contain "email:string" in its schema.');
|
|
124
|
+
}
|
|
125
|
+
// Use processProtectedData from dataprotector
|
|
126
|
+
const result = await dataProtector.processProtectedData({
|
|
127
|
+
defaultWorkerpool: vWorkerpoolAddressOrEns,
|
|
128
|
+
protectedData: vDatasetAddress,
|
|
189
129
|
app: vDappAddressOrENS,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
workerpoolmaxprice: workerpoolorder.workerpoolprice,
|
|
195
|
-
tag: ['tee', 'scone'],
|
|
130
|
+
// userWhitelist: vDappWhitelistAddress, // Removed due to bug in dataprotector v2.0.0-beta.20
|
|
131
|
+
dataMaxPrice: vDataMaxPrice,
|
|
132
|
+
appMaxPrice: vAppMaxPrice,
|
|
133
|
+
workerpoolMaxPrice: vWorkerpoolMaxPrice,
|
|
196
134
|
workerpool: vWorkerpoolAddressOrEns,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
iexec_args: vLabel,
|
|
203
|
-
},
|
|
135
|
+
args: vLabel,
|
|
136
|
+
inputFiles: [],
|
|
137
|
+
secrets,
|
|
138
|
+
useVoucher: vUseVoucher,
|
|
139
|
+
waitForResult: false,
|
|
204
140
|
});
|
|
205
|
-
const requestorder = await iexec.order.signRequestorder(requestorderToSign);
|
|
206
|
-
// Match orders and compute task ID
|
|
207
|
-
const { dealid } = await iexec.order.matchOrders({
|
|
208
|
-
apporder: apporder,
|
|
209
|
-
datasetorder: datasetorder,
|
|
210
|
-
workerpoolorder: workerpoolorder,
|
|
211
|
-
requestorder: requestorder,
|
|
212
|
-
}, { useVoucher: vUseVoucher });
|
|
213
|
-
const taskId = await iexec.deal.computeTaskId(dealid, 0);
|
|
214
141
|
return {
|
|
215
|
-
taskId,
|
|
142
|
+
taskId: result.taskId,
|
|
216
143
|
};
|
|
217
144
|
}
|
|
218
145
|
catch (error) {
|
|
146
|
+
// Protocol error detected, re-throwing as-is
|
|
147
|
+
if (error?.isProtocolError === true) {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
// Handle protocol errors - this will throw if it's an ApiCallError
|
|
151
|
+
// handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true
|
|
219
152
|
handleIfProtocolError(error);
|
|
153
|
+
// If we reach here, it's not a protocol error
|
|
154
|
+
// Check if it's a WorkflowError from processProtectedData by checking the message
|
|
155
|
+
const isProcessProtectedDataError = error instanceof Error &&
|
|
156
|
+
error.message === 'Failed to process protected data';
|
|
157
|
+
if (isProcessProtectedDataError) {
|
|
158
|
+
const cause = error?.cause;
|
|
159
|
+
// Return unwrapped cause (the actual Error object)
|
|
160
|
+
// error.cause should be an Error, but ensure it is
|
|
161
|
+
const unwrappedCause = cause instanceof Error ? cause : error;
|
|
162
|
+
throw new WorkflowError({
|
|
163
|
+
message: 'Failed to sendEmail',
|
|
164
|
+
errorCause: unwrappedCause,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// For all other errors
|
|
220
168
|
throw new WorkflowError({
|
|
221
169
|
message: 'Failed to sendEmail',
|
|
222
170
|
errorCause: error,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sendEmail.js","sourceRoot":"","sources":["../../src/web3mail/sendEmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"sendEmail.js","sourceRoot":"","sources":["../../src/web3mail/sendEmail.ts"],"names":[],"mappings":"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"}
|
package/dist/web3mail/types.d.ts
CHANGED
|
@@ -5,19 +5,39 @@ export type ENS = string;
|
|
|
5
5
|
export type AddressOrENS = Address | ENS;
|
|
6
6
|
export type Address = string;
|
|
7
7
|
export type TimeStamp = string;
|
|
8
|
+
export type GrantedAccess = {
|
|
9
|
+
dataset: string;
|
|
10
|
+
datasetprice: string;
|
|
11
|
+
volume: string;
|
|
12
|
+
tag: string;
|
|
13
|
+
apprestrict: string;
|
|
14
|
+
workerpoolrestrict: string;
|
|
15
|
+
requesterrestrict: string;
|
|
16
|
+
salt: string;
|
|
17
|
+
sign: string;
|
|
18
|
+
remainingAccess: number;
|
|
19
|
+
};
|
|
8
20
|
export type Contact = {
|
|
9
21
|
address: Address;
|
|
10
22
|
owner: Address;
|
|
11
23
|
accessGrantTimestamp: TimeStamp;
|
|
12
24
|
isUserStrict: boolean;
|
|
13
|
-
name
|
|
25
|
+
name?: string;
|
|
14
26
|
remainingAccess: number;
|
|
15
27
|
accessPrice: number;
|
|
28
|
+
grantedAccess: GrantedAccess;
|
|
16
29
|
};
|
|
17
30
|
export type SendEmailParams = {
|
|
18
31
|
emailSubject: string;
|
|
19
32
|
emailContent: string;
|
|
20
|
-
protectedData
|
|
33
|
+
protectedData?: Address;
|
|
34
|
+
/**
|
|
35
|
+
* Granted access to process.
|
|
36
|
+
* use prepareBulkRequest of dataprotector to create a bulk request.
|
|
37
|
+
* if not provided, the single message will be processed.
|
|
38
|
+
*/
|
|
39
|
+
grantedAccess?: GrantedAccess[];
|
|
40
|
+
maxProtectedDataPerTask?: number;
|
|
21
41
|
contentType?: string;
|
|
22
42
|
senderName?: string;
|
|
23
43
|
label?: string;
|
|
@@ -32,6 +52,7 @@ export type FetchMyContactsParams = {
|
|
|
32
52
|
* Get contacts for this specific user only
|
|
33
53
|
*/
|
|
34
54
|
isUserStrict?: boolean;
|
|
55
|
+
bulkOnly?: boolean;
|
|
35
56
|
};
|
|
36
57
|
export type FetchUserContactsParams = {
|
|
37
58
|
/**
|
|
@@ -39,9 +60,23 @@ export type FetchUserContactsParams = {
|
|
|
39
60
|
*/
|
|
40
61
|
userAddress: Address;
|
|
41
62
|
} & FetchMyContactsParams;
|
|
42
|
-
|
|
63
|
+
type SendEmailSingleResponse = {
|
|
43
64
|
taskId: string;
|
|
44
65
|
};
|
|
66
|
+
type SendEmailBulkResponse = {
|
|
67
|
+
tasks: {
|
|
68
|
+
bulkIndex: number;
|
|
69
|
+
taskId: string;
|
|
70
|
+
dealId: string;
|
|
71
|
+
}[];
|
|
72
|
+
};
|
|
73
|
+
export type SendEmailResponse<Params = {
|
|
74
|
+
protectedData: Address;
|
|
75
|
+
}> = Params extends {
|
|
76
|
+
grantedAccess: GrantedAccess[];
|
|
77
|
+
} ? SendEmailBulkResponse : never & Params extends {
|
|
78
|
+
protectedData: Address;
|
|
79
|
+
} ? SendEmailSingleResponse : never;
|
|
45
80
|
/**
|
|
46
81
|
* Configuration options for Web3Mail.
|
|
47
82
|
*/
|
|
@@ -83,3 +118,4 @@ export type Web3MailConfigOptions = {
|
|
|
83
118
|
*/
|
|
84
119
|
allowExperimentalNetworks?: boolean;
|
|
85
120
|
};
|
|
121
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iexec/web3mail",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-nightly-b2a0e93",
|
|
4
4
|
"description": "This product enables users to confidentially store data–such as mail address, documents, personal information ...",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,15 +49,15 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@ethersproject/bytes": "^5.7.0",
|
|
51
51
|
"@ethersproject/random": "^5.7.0",
|
|
52
|
+
"@iexec/dataprotector": "^2.0.0-beta.21",
|
|
52
53
|
"buffer": "^6.0.3",
|
|
53
54
|
"ethers": "^6.13.2",
|
|
54
55
|
"graphql-request": "^6.1.0",
|
|
55
|
-
"iexec": "^8.
|
|
56
|
+
"iexec": "^8.22.0",
|
|
56
57
|
"kubo-rpc-client": "^4.1.1",
|
|
57
58
|
"yup": "^1.1.1"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
|
-
"@iexec/dataprotector": "^2.0.0-beta.18",
|
|
61
61
|
"@jest/globals": "^29.7.0",
|
|
62
62
|
"@swc/core": "^1.3.96",
|
|
63
63
|
"@swc/jest": "^0.2.29",
|
package/src/config/config.ts
CHANGED
|
@@ -38,7 +38,6 @@ const CHAIN_CONFIG: Record<number, ChainConfig> = {
|
|
|
38
38
|
ipfsGateway: 'https://ipfs-gateway.arbitrum-sepolia-testnet.iex.ec',
|
|
39
39
|
ipfsUploadUrl: 'https://ipfs-upload.arbitrum-sepolia-testnet.iex.ec',
|
|
40
40
|
whitelistSmartContract: '0x8d46d40840f1Aa2264F96184Ffadf04e5D573B9B',
|
|
41
|
-
isExperimental: true,
|
|
42
41
|
},
|
|
43
42
|
42161: {
|
|
44
43
|
name: 'arbitrum-mainnet',
|
|
@@ -71,20 +71,24 @@ export const getValidContact = async (
|
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
// Convert protectedData[] into Contact[] using the map for constant time lookups
|
|
74
|
-
return protectedDataList
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
return protectedDataList
|
|
75
|
+
.map(({ id, name }) => {
|
|
76
|
+
const contact = contactsMap.get(id);
|
|
77
|
+
if (contact) {
|
|
78
|
+
return {
|
|
79
|
+
address: id,
|
|
80
|
+
name: name,
|
|
81
|
+
remainingAccess: contact.remainingAccess,
|
|
82
|
+
accessPrice: contact.accessPrice,
|
|
83
|
+
owner: contact.owner,
|
|
84
|
+
accessGrantTimestamp: contact.accessGrantTimestamp,
|
|
85
|
+
isUserStrict: contact.isUserStrict,
|
|
86
|
+
grantedAccess: contact.grantedAccess,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
})
|
|
91
|
+
.filter((contact) => contact !== null && contact !== undefined);
|
|
88
92
|
} catch (error) {
|
|
89
93
|
throw new WorkflowError({
|
|
90
94
|
message: 'Failed to fetch subgraph',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AbstractProvider, AbstractSigner, Eip1193Provider } from 'ethers';
|
|
2
2
|
import { IExec } from 'iexec';
|
|
3
|
+
import { IExecDataProtectorCore } from '@iexec/dataprotector';
|
|
3
4
|
import { GraphQLClient } from 'graphql-request';
|
|
4
5
|
import { fetchUserContacts } from './fetchUserContacts.js';
|
|
5
6
|
import { fetchMyContacts } from './fetchMyContacts.js';
|
|
@@ -34,6 +35,7 @@ interface Web3mailResolvedConfig {
|
|
|
34
35
|
ipfsGateway: string;
|
|
35
36
|
defaultWorkerpool: string;
|
|
36
37
|
iexec: IExec;
|
|
38
|
+
dataProtector: IExecDataProtectorCore;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
export class IExecWeb3mail {
|
|
@@ -51,6 +53,8 @@ export class IExecWeb3mail {
|
|
|
51
53
|
|
|
52
54
|
private iexec!: IExec;
|
|
53
55
|
|
|
56
|
+
private dataProtector!: IExecDataProtectorCore;
|
|
57
|
+
|
|
54
58
|
private initPromise: Promise<void> | null = null;
|
|
55
59
|
|
|
56
60
|
private ethProvider: EthersCompatibleProvider;
|
|
@@ -75,6 +79,7 @@ export class IExecWeb3mail {
|
|
|
75
79
|
this.ipfsGateway = config.ipfsGateway;
|
|
76
80
|
this.defaultWorkerpool = config.defaultWorkerpool;
|
|
77
81
|
this.iexec = config.iexec;
|
|
82
|
+
this.dataProtector = config.dataProtector;
|
|
78
83
|
});
|
|
79
84
|
}
|
|
80
85
|
return this.initPromise;
|
|
@@ -105,7 +110,9 @@ export class IExecWeb3mail {
|
|
|
105
110
|
});
|
|
106
111
|
}
|
|
107
112
|
|
|
108
|
-
async sendEmail
|
|
113
|
+
async sendEmail<Params extends SendEmailParams>(
|
|
114
|
+
args: Params
|
|
115
|
+
): Promise<SendEmailResponse<Params>> {
|
|
109
116
|
await this.init();
|
|
110
117
|
await isValidProvider(this.iexec);
|
|
111
118
|
return sendEmail({
|
|
@@ -113,12 +120,13 @@ export class IExecWeb3mail {
|
|
|
113
120
|
workerpoolAddressOrEns:
|
|
114
121
|
args.workerpoolAddressOrEns || this.defaultWorkerpool,
|
|
115
122
|
iexec: this.iexec,
|
|
123
|
+
dataProtector: this.dataProtector,
|
|
116
124
|
ipfsNode: this.ipfsNode,
|
|
117
125
|
ipfsGateway: this.ipfsGateway,
|
|
118
126
|
dappAddressOrENS: this.dappAddressOrENS,
|
|
119
127
|
dappWhitelistAddress: this.dappWhitelistAddress,
|
|
120
128
|
graphQLClient: this.graphQLClient,
|
|
121
|
-
})
|
|
129
|
+
}) as Promise<SendEmailResponse<Params>>;
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
private async resolveConfig(): Promise<Web3mailResolvedConfig> {
|
|
@@ -184,6 +192,17 @@ export class IExecWeb3mail {
|
|
|
184
192
|
throw new Error(`Failed to create GraphQLClient: ${error.message}`);
|
|
185
193
|
}
|
|
186
194
|
|
|
195
|
+
const dataProtector = new IExecDataProtectorCore(this.ethProvider, {
|
|
196
|
+
iexecOptions: {
|
|
197
|
+
ipfsGatewayURL: ipfsGateway,
|
|
198
|
+
...this.options?.iexecOptions,
|
|
199
|
+
allowExperimentalNetworks: this.options.allowExperimentalNetworks,
|
|
200
|
+
},
|
|
201
|
+
ipfsGateway,
|
|
202
|
+
ipfsNode,
|
|
203
|
+
subgraphUrl,
|
|
204
|
+
});
|
|
205
|
+
|
|
187
206
|
return {
|
|
188
207
|
dappAddressOrENS,
|
|
189
208
|
dappWhitelistAddress: dappWhitelistAddress.toLowerCase(),
|
|
@@ -192,6 +211,7 @@ export class IExecWeb3mail {
|
|
|
192
211
|
ipfsNode,
|
|
193
212
|
ipfsGateway,
|
|
194
213
|
iexec,
|
|
214
|
+
dataProtector,
|
|
195
215
|
};
|
|
196
216
|
}
|
|
197
217
|
}
|
|
@@ -16,6 +16,7 @@ export const fetchMyContacts = async ({
|
|
|
16
16
|
dappAddressOrENS = throwIfMissing(),
|
|
17
17
|
dappWhitelistAddress = throwIfMissing(),
|
|
18
18
|
isUserStrict = false,
|
|
19
|
+
bulkOnly = false,
|
|
19
20
|
}: IExecConsumer &
|
|
20
21
|
SubgraphConsumer &
|
|
21
22
|
DappAddressConsumer &
|
|
@@ -33,5 +34,6 @@ export const fetchMyContacts = async ({
|
|
|
33
34
|
dappWhitelistAddress,
|
|
34
35
|
userAddress,
|
|
35
36
|
isUserStrict: vIsUserStrict,
|
|
37
|
+
bulkOnly,
|
|
36
38
|
});
|
|
37
39
|
};
|