@iexec/web3mail 1.4.0 → 1.6.0-nightly-8729cd2

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.
@@ -12,7 +12,7 @@ import {
12
12
  isEnsTest,
13
13
  throwIfMissing,
14
14
  } from '../utils/validators.js';
15
- import { Contact, FetchUserContactsParams } from './types.js';
15
+ import { Contact, FetchUserContactsParams, GrantedAccess } from './types.js';
16
16
  import {
17
17
  DappAddressConsumer,
18
18
  DappWhitelistAddressConsumer,
@@ -27,6 +27,7 @@ export const fetchUserContacts = async ({
27
27
  dappWhitelistAddress = throwIfMissing(),
28
28
  userAddress,
29
29
  isUserStrict = false,
30
+ bulkOnly = false,
30
31
  }: IExecConsumer &
31
32
  SubgraphConsumer &
32
33
  DappAddressConsumer &
@@ -47,6 +48,7 @@ export const fetchUserContacts = async ({
47
48
  const vIsUserStrict = booleanSchema()
48
49
  .label('isUserStrict')
49
50
  .validateSync(isUserStrict);
51
+ const vBulkOnly = booleanSchema().label('bulkOnly').validateSync(bulkOnly);
50
52
 
51
53
  try {
52
54
  const [dappOrders, whitelistOrders] = await Promise.all([
@@ -55,15 +57,16 @@ export const fetchUserContacts = async ({
55
57
  userAddress: vUserAddress,
56
58
  appAddress: vDappAddressOrENS,
57
59
  isUserStrict: vIsUserStrict,
60
+ bulkOnly: vBulkOnly,
58
61
  }),
59
62
  fetchAllOrdersByApp({
60
63
  iexec,
61
64
  userAddress: vUserAddress,
62
65
  appAddress: vDappWhitelistAddress,
63
66
  isUserStrict: vIsUserStrict,
67
+ bulkOnly: vBulkOnly,
64
68
  }),
65
69
  ]);
66
-
67
70
  const orders = dappOrders.concat(whitelistOrders);
68
71
  const myContacts: Omit<Contact, 'name'>[] = [];
69
72
  let web3DappResolvedAddress = vDappAddressOrENS;
@@ -77,13 +80,25 @@ export const fetchUserContacts = async ({
77
80
  order.order.apprestrict.toLowerCase() ===
78
81
  vDappWhitelistAddress.toLowerCase()
79
82
  ) {
80
- const contact = {
83
+ const contact: Contact = {
81
84
  address: order.order.dataset.toLowerCase(),
82
85
  owner: order.signer.toLowerCase(),
83
86
  remainingAccess: order.remaining,
84
87
  accessPrice: order.order.datasetprice,
85
88
  accessGrantTimestamp: order.publicationTimestamp,
86
89
  isUserStrict: order.order.requesterrestrict !== ZeroAddress,
90
+ grantedAccess: {
91
+ dataset: order.order.dataset,
92
+ datasetprice: order.order.datasetprice.toString(),
93
+ volume: order.order.volume.toString(),
94
+ tag: order.order.tag,
95
+ apprestrict: order.order.apprestrict,
96
+ workerpoolrestrict: order.order.workerpoolrestrict,
97
+ requesterrestrict: order.order.requesterrestrict,
98
+ salt: order.order.salt,
99
+ sign: order.order.sign,
100
+ remainingAccess: order.remaining,
101
+ } as GrantedAccess,
87
102
  };
88
103
  myContacts.push(contact);
89
104
  }
@@ -94,7 +109,6 @@ export const fetchUserContacts = async ({
94
109
  return await getValidContact(graphQLClient, myContacts);
95
110
  } catch (error) {
96
111
  handleIfProtocolError(error);
97
-
98
112
  throw new WorkflowError({
99
113
  message: 'Failed to fetch user contacts',
100
114
  errorCause: error,
@@ -107,23 +121,24 @@ async function fetchAllOrdersByApp({
107
121
  userAddress,
108
122
  appAddress,
109
123
  isUserStrict,
124
+ bulkOnly,
110
125
  }: {
111
126
  iexec: IExec;
112
127
  userAddress: string;
113
128
  appAddress: string;
114
129
  isUserStrict: boolean;
130
+ bulkOnly?: boolean;
115
131
  }): Promise<PublishedDatasetorder[]> {
116
- const ordersFirstPage = iexec.orderbook.fetchDatasetOrderbook(
117
- ANY_DATASET_ADDRESS,
118
- {
119
- app: appAddress,
120
- requester: userAddress,
121
- isAppStrict: true,
122
- isRequesterStrict: isUserStrict,
123
- // Use maxPageSize here to avoid too many round-trips (we want everything anyway)
124
- pageSize: 1000,
125
- }
126
- );
132
+ const ordersFirstPage = iexec.orderbook.fetchDatasetOrderbook({
133
+ dataset: ANY_DATASET_ADDRESS,
134
+ app: appAddress,
135
+ requester: userAddress,
136
+ isAppStrict: true,
137
+ isRequesterStrict: isUserStrict,
138
+ bulkOnly,
139
+ // Use maxPageSize here to avoid too many round-trips (we want everything anyway)
140
+ pageSize: 1000,
141
+ });
127
142
  const { orders: allOrders } = await autoPaginateRequest({
128
143
  request: ordersFirstPage,
129
144
  });
@@ -1,6 +1,7 @@
1
1
  import { IExec } from 'iexec';
2
2
  import { AddressOrENS } from './types.js';
3
3
  import { GraphQLClient } from 'graphql-request';
4
+ import { IExecDataProtectorCore } from '@iexec/dataprotector';
4
5
 
5
6
  export type ProtectedDataQuery = {
6
7
  id: string;
@@ -31,6 +32,8 @@ export type IExecConsumer = {
31
32
  iexec: IExec;
32
33
  };
33
34
 
35
+ export type DataProtectorConsumer = { dataProtector: IExecDataProtectorCore };
36
+
34
37
  export type SubgraphConsumer = {
35
38
  graphQLClient: GraphQLClient;
36
39
  };
@@ -1,18 +1,16 @@
1
1
  import { Buffer } from 'buffer';
2
+ import { ProcessBulkRequestResponse } from '@iexec/dataprotector';
2
3
  import {
3
- CALLBACK_WEB3MAIL,
4
4
  DEFAULT_CONTENT_TYPE,
5
5
  MAX_DESIRED_APP_ORDER_PRICE,
6
6
  MAX_DESIRED_DATA_ORDER_PRICE,
7
7
  MAX_DESIRED_WORKERPOOL_ORDER_PRICE,
8
8
  } from '../config/config.js';
9
9
  import { handleIfProtocolError, WorkflowError } from '../utils/errors.js';
10
- import { generateSecureUniqueId } from '../utils/generateUniqueId.js';
11
10
  import * as ipfs from '../utils/ipfs-service.js';
12
11
  import { checkProtectedDataValidity } from '../utils/subgraphQuery.js';
13
12
  import {
14
13
  addressOrEnsSchema,
15
- addressSchema,
16
14
  booleanSchema,
17
15
  contentTypeSchema,
18
16
  emailContentSchema,
@@ -22,14 +20,11 @@ import {
22
20
  senderNameSchema,
23
21
  throwIfMissing,
24
22
  } from '../utils/validators.js';
25
- import {
26
- checkUserVoucher,
27
- filterWorkerpoolOrders,
28
- } from './sendEmail.models.js';
29
- import { SendEmailParams, SendEmailResponse } from './types.js';
23
+ import { SendEmailParams, SendEmailSingleResponse } from './types.js';
30
24
  import {
31
25
  DappAddressConsumer,
32
26
  DappWhitelistAddressConsumer,
27
+ DataProtectorConsumer,
33
28
  IExecConsumer,
34
29
  IpfsGatewayConfigConsumer,
35
30
  IpfsNodeConfigConsumer,
@@ -41,9 +36,9 @@ export type SendEmail = typeof sendEmail;
41
36
  export const sendEmail = async ({
42
37
  graphQLClient = throwIfMissing(),
43
38
  iexec = throwIfMissing(),
44
- workerpoolAddressOrEns,
39
+ dataProtector = throwIfMissing(),
40
+ workerpoolAddressOrEns = throwIfMissing(),
45
41
  dappAddressOrENS,
46
- dappWhitelistAddress,
47
42
  ipfsNode,
48
43
  ipfsGateway,
49
44
  emailSubject,
@@ -55,6 +50,8 @@ export const sendEmail = async ({
55
50
  workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE,
56
51
  senderName,
57
52
  protectedData,
53
+ grantedAccess,
54
+ maxProtectedDataPerTask,
58
55
  useVoucher = false,
59
56
  }: IExecConsumer &
60
57
  SubgraphConsumer &
@@ -62,182 +59,55 @@ export const sendEmail = async ({
62
59
  DappWhitelistAddressConsumer &
63
60
  IpfsNodeConfigConsumer &
64
61
  IpfsGatewayConfigConsumer &
65
- SendEmailParams): Promise<SendEmailResponse> => {
66
- const vDatasetAddress = addressOrEnsSchema()
67
- .required()
68
- .label('protectedData')
69
- .validateSync(protectedData);
70
- const vEmailSubject = emailSubjectSchema()
71
- .required()
72
- .label('emailSubject')
73
- .validateSync(emailSubject);
74
- const vEmailContent = emailContentSchema()
75
- .required()
76
- .label('emailContent')
77
- .validateSync(emailContent);
78
- const vContentType = contentTypeSchema()
79
- .required()
80
- .label('contentType')
81
- .validateSync(contentType);
82
- const vSenderName = senderNameSchema()
83
- .label('senderName')
84
- .validateSync(senderName);
85
- const vLabel = labelSchema().label('label').validateSync(label);
86
- const vWorkerpoolAddressOrEns = addressOrEnsSchema()
87
- .required()
88
- .label('WorkerpoolAddressOrEns')
89
- .validateSync(workerpoolAddressOrEns);
90
- const vDappAddressOrENS = addressOrEnsSchema()
91
- .required()
92
- .label('dappAddressOrENS')
93
- .validateSync(dappAddressOrENS);
94
- const vDappWhitelistAddress = addressSchema()
95
- .required()
96
- .label('dappWhitelistAddress')
97
- .validateSync(dappWhitelistAddress);
98
- const vDataMaxPrice = positiveNumberSchema()
99
- .label('dataMaxPrice')
100
- .validateSync(dataMaxPrice);
101
- const vAppMaxPrice = positiveNumberSchema()
102
- .label('appMaxPrice')
103
- .validateSync(appMaxPrice);
104
- const vWorkerpoolMaxPrice = positiveNumberSchema()
105
- .label('workerpoolMaxPrice')
106
- .validateSync(workerpoolMaxPrice);
107
- const vUseVoucher = booleanSchema()
108
- .label('useVoucher')
109
- .validateSync(useVoucher);
110
-
111
- // Check protected data schema through subgraph
112
- const isValidProtectedData = await checkProtectedDataValidity(
113
- graphQLClient,
114
- vDatasetAddress
115
- );
116
- if (!isValidProtectedData) {
117
- throw new Error(
118
- 'This protected data does not contain "email:string" in its schema.'
119
- );
120
- }
121
-
122
- const requesterAddress = await iexec.wallet.getAddress();
123
-
124
- let userVoucher;
125
- if (vUseVoucher) {
126
- try {
127
- userVoucher = await iexec.voucher.showUserVoucher(requesterAddress);
128
- checkUserVoucher({ userVoucher });
129
- } catch (err) {
130
- if (err?.message?.startsWith('No Voucher found for address')) {
131
- throw new Error(
132
- 'Oops, it seems your wallet is not associated with any voucher. Check on https://builder.iex.ec/'
133
- );
134
- }
135
- throw err;
136
- }
137
- }
138
-
62
+ SendEmailParams &
63
+ DataProtectorConsumer): Promise<
64
+ ProcessBulkRequestResponse | SendEmailSingleResponse
65
+ > => {
139
66
  try {
140
- const [
141
- datasetorderForApp,
142
- datasetorderForWhitelist,
143
- apporder,
144
- workerpoolorder,
145
- ] = await Promise.all([
146
- // Fetch dataset order for web3mail app
147
- iexec.orderbook
148
- .fetchDatasetOrderbook(vDatasetAddress, {
149
- app: dappAddressOrENS,
150
- requester: requesterAddress,
151
- })
152
- .then((datasetOrderbook) => {
153
- const desiredPriceDataOrderbook = datasetOrderbook.orders.filter(
154
- (order) => order.order.datasetprice <= vDataMaxPrice
155
- );
156
- return desiredPriceDataOrderbook[0]?.order; // may be undefined
157
- }),
158
- // Fetch dataset order for web3mail whitelist
159
- iexec.orderbook
160
- .fetchDatasetOrderbook(vDatasetAddress, {
161
- app: vDappWhitelistAddress,
162
- requester: requesterAddress,
163
- })
164
- .then((datasetOrderbook) => {
165
- const desiredPriceDataOrderbook = datasetOrderbook.orders.filter(
166
- (order) => order.order.datasetprice <= vDataMaxPrice
167
- );
168
- return desiredPriceDataOrderbook[0]?.order; // may be undefined
169
- }),
170
- // Fetch app order
171
- iexec.orderbook
172
- .fetchAppOrderbook(dappAddressOrENS, {
173
- minTag: ['tee', 'scone'],
174
- maxTag: ['tee', 'scone'],
175
- workerpool: workerpoolAddressOrEns,
176
- })
177
- .then((appOrderbook) => {
178
- const desiredPriceAppOrderbook = appOrderbook.orders.filter(
179
- (order) => order.order.appprice <= vAppMaxPrice
180
- );
181
- const desiredPriceAppOrder = desiredPriceAppOrderbook[0]?.order;
182
- if (!desiredPriceAppOrder) {
183
- throw new Error('No App order found for the desired price');
184
- }
185
- return desiredPriceAppOrder;
186
- }),
187
- // Fetch workerpool order for App or AppWhitelist
188
- Promise.all([
189
- // for app
190
- iexec.orderbook.fetchWorkerpoolOrderbook({
191
- workerpool: workerpoolAddressOrEns,
192
- app: vDappAddressOrENS,
193
- dataset: vDatasetAddress,
194
- requester: requesterAddress, // public orders + user specific orders
195
- isRequesterStrict: useVoucher, // If voucher, we only want user specific orders
196
- minTag: ['tee', 'scone'],
197
- maxTag: ['tee', 'scone'],
198
- category: 0,
199
- }),
200
- // for app whitelist
201
- iexec.orderbook.fetchWorkerpoolOrderbook({
202
- workerpool: workerpoolAddressOrEns,
203
- app: vDappWhitelistAddress,
204
- dataset: vDatasetAddress,
205
- requester: requesterAddress, // public orders + user specific orders
206
- isRequesterStrict: useVoucher, // If voucher, we only want user specific orders
207
- minTag: ['tee', 'scone'],
208
- maxTag: ['tee', 'scone'],
209
- category: 0,
210
- }),
211
- ]).then(
212
- ([workerpoolOrderbookForApp, workerpoolOrderbookForAppWhitelist]) => {
213
- const desiredPriceWorkerpoolOrder = filterWorkerpoolOrders({
214
- workerpoolOrders: [
215
- ...workerpoolOrderbookForApp.orders,
216
- ...workerpoolOrderbookForAppWhitelist.orders,
217
- ],
218
- workerpoolMaxPrice: vWorkerpoolMaxPrice,
219
- useVoucher: vUseVoucher,
220
- userVoucher,
221
- });
222
- if (!desiredPriceWorkerpoolOrder) {
223
- throw new Error('No Workerpool order found for the desired price');
224
- }
225
- return desiredPriceWorkerpoolOrder;
226
- }
227
- ),
228
- ]);
229
-
230
- if (!workerpoolorder) {
231
- throw new Error('No Workerpool order found for the desired price');
232
- }
67
+ const vUseVoucher = booleanSchema()
68
+ .label('useVoucher')
69
+ .validateSync(useVoucher);
70
+ const vWorkerpoolAddressOrEns = addressOrEnsSchema()
71
+ .required()
72
+ .label('WorkerpoolAddressOrEns')
73
+ .validateSync(workerpoolAddressOrEns);
74
+ const vSenderName = senderNameSchema()
75
+ .label('senderName')
76
+ .validateSync(senderName);
77
+ const vEmailSubject = emailSubjectSchema()
78
+ .required()
79
+ .label('emailSubject')
80
+ .validateSync(emailSubject);
81
+ const vEmailContent = emailContentSchema()
82
+ .required()
83
+ .label('emailContent')
84
+ .validateSync(emailContent);
85
+ const vContentType = contentTypeSchema()
86
+ .required()
87
+ .label('contentType')
88
+ .validateSync(contentType);
89
+ const vLabel = labelSchema().label('label').validateSync(label);
233
90
 
234
- const datasetorder = datasetorderForApp || datasetorderForWhitelist;
235
- if (!datasetorder) {
236
- throw new Error('No Dataset order found for the desired price');
237
- }
91
+ const vDappAddressOrENS = addressOrEnsSchema()
92
+ .required()
93
+ .label('dappAddressOrENS')
94
+ .validateSync(dappAddressOrENS);
95
+ // TODO: remove this once we have a way to pass appWhitelist to processProtectedData function
96
+ // const vDappWhitelistAddress = addressSchema()
97
+ // .required()
98
+ // .label('dappWhitelistAddress')
99
+ // .validateSync(dappWhitelistAddress);
100
+ const vDataMaxPrice = positiveNumberSchema()
101
+ .label('dataMaxPrice')
102
+ .validateSync(dataMaxPrice);
103
+ const vAppMaxPrice = positiveNumberSchema()
104
+ .label('appMaxPrice')
105
+ .validateSync(appMaxPrice);
106
+ const vWorkerpoolMaxPrice = positiveNumberSchema()
107
+ .label('workerpoolMaxPrice')
108
+ .validateSync(workerpoolMaxPrice);
238
109
 
239
- // Push requester secrets
240
- const requesterSecretId = generateSecureUniqueId(16);
110
+ // Encrypt email content
241
111
  const emailContentEncryptionKey = iexec.dataset.generateEncryptionKey();
242
112
  const encryptedFile = await iexec.dataset
243
113
  .encrypt(Buffer.from(vEmailContent, 'utf8'), emailContentEncryptionKey)
@@ -247,10 +117,12 @@ export const sendEmail = async ({
247
117
  errorCause: e,
248
118
  });
249
119
  });
120
+
121
+ // Push email message to IPFS
250
122
  const cid = await ipfs
251
123
  .add(encryptedFile, {
252
- ipfsNode: ipfsNode,
253
- ipfsGateway: ipfsGateway,
124
+ ipfsNode,
125
+ ipfsGateway,
254
126
  })
255
127
  .catch((e) => {
256
128
  throw new WorkflowError({
@@ -260,55 +132,109 @@ export const sendEmail = async ({
260
132
  });
261
133
  const multiaddr = `/ipfs/${cid}`;
262
134
 
263
- await iexec.secrets.pushRequesterSecret(
264
- requesterSecretId,
265
- JSON.stringify({
135
+ // Prepare secrets for the requester
136
+ // Use a positive integer as secret ID (required by iexec)
137
+ // Using "1" as a fixed ID for the requester secret
138
+ const requesterSecretId = 1;
139
+ const secrets = {
140
+ [requesterSecretId]: JSON.stringify({
141
+ senderName: vSenderName,
266
142
  emailSubject: vEmailSubject,
267
143
  emailContentMultiAddr: multiaddr,
268
144
  contentType: vContentType,
269
- senderName: vSenderName,
270
145
  emailContentEncryptionKey,
271
- useCallback: true,
272
- })
146
+ }),
147
+ };
148
+ // Bulk processing
149
+ if (grantedAccess) {
150
+ const vMaxProtectedDataPerTask = positiveNumberSchema()
151
+ .label('maxProtectedDataPerTask')
152
+ .validateSync(maxProtectedDataPerTask);
153
+
154
+ const bulkRequest = await dataProtector.prepareBulkRequest({
155
+ app: vDappAddressOrENS,
156
+ appMaxPrice: vAppMaxPrice,
157
+ workerpoolMaxPrice: vWorkerpoolMaxPrice,
158
+ workerpool: vWorkerpoolAddressOrEns,
159
+ args: vLabel,
160
+ inputFiles: [],
161
+ secrets,
162
+ bulkOrders: grantedAccess,
163
+ maxProtectedDataPerTask: vMaxProtectedDataPerTask,
164
+ });
165
+ const processBulkRequestResponse: ProcessBulkRequestResponse =
166
+ await dataProtector.processBulkRequest({
167
+ bulkRequest: bulkRequest.bulkRequest,
168
+ useVoucher: vUseVoucher,
169
+ workerpool: vWorkerpoolAddressOrEns,
170
+ });
171
+ return processBulkRequestResponse;
172
+ }
173
+
174
+ // Single processing mode - protectedData is required
175
+ const vDatasetAddress = addressOrEnsSchema()
176
+ .required()
177
+ .label('protectedData')
178
+ .validateSync(protectedData);
179
+ // Check protected data validity through subgraph
180
+ const isValidProtectedData = await checkProtectedDataValidity(
181
+ graphQLClient,
182
+ vDatasetAddress
273
183
  );
184
+ if (!isValidProtectedData) {
185
+ throw new Error(
186
+ 'This protected data does not contain "email:string" in its schema.'
187
+ );
188
+ }
274
189
 
275
- const requestorderToSign = await iexec.order.createRequestorder({
190
+ // Use processProtectedData from dataprotector
191
+ const result = await dataProtector.processProtectedData({
192
+ defaultWorkerpool: vWorkerpoolAddressOrEns,
193
+ protectedData: vDatasetAddress,
276
194
  app: vDappAddressOrENS,
277
- category: workerpoolorder.category,
278
- dataset: vDatasetAddress,
279
- datasetmaxprice: datasetorder.datasetprice,
280
- appmaxprice: apporder.appprice,
281
- workerpoolmaxprice: workerpoolorder.workerpoolprice,
282
- tag: ['tee', 'scone'],
195
+ // userWhitelist: vDappWhitelistAddress, // Removed due to bug in dataprotector v2.0.0-beta.20
196
+ dataMaxPrice: vDataMaxPrice,
197
+ appMaxPrice: vAppMaxPrice,
198
+ workerpoolMaxPrice: vWorkerpoolMaxPrice,
283
199
  workerpool: vWorkerpoolAddressOrEns,
284
- callback: CALLBACK_WEB3MAIL,
285
- params: {
286
- iexec_secrets: {
287
- 1: requesterSecretId,
288
- },
289
- iexec_args: vLabel,
290
- },
200
+ args: vLabel,
201
+ inputFiles: [],
202
+ secrets,
203
+ useVoucher: vUseVoucher,
204
+ waitForResult: false,
291
205
  });
292
- const requestorder = await iexec.order.signRequestorder(requestorderToSign);
293
-
294
- // Match orders and compute task ID
295
- const { dealid } = await iexec.order.matchOrders(
296
- {
297
- apporder: apporder,
298
- datasetorder: datasetorder,
299
- workerpoolorder: workerpoolorder,
300
- requestorder: requestorder,
301
- },
302
- { useVoucher: vUseVoucher }
303
- );
304
- const taskId = await iexec.deal.computeTaskId(dealid, 0);
305
206
 
306
207
  return {
307
- taskId,
208
+ taskId: result.taskId,
308
209
  };
309
210
  } catch (error) {
211
+ // Protocol error detected, re-throwing as-is
212
+ if ((error as any)?.isProtocolError === true) {
213
+ throw error;
214
+ }
215
+
216
+ // Handle protocol errors - this will throw if it's an ApiCallError
217
+ // handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true
310
218
  handleIfProtocolError(error);
311
219
 
220
+ // If we reach here, it's not a protocol error
221
+ // Check if it's a WorkflowError from processProtectedData by checking the message
222
+ const isProcessProtectedDataError =
223
+ error instanceof Error &&
224
+ error.message === 'Failed to process protected data';
225
+
226
+ if (isProcessProtectedDataError) {
227
+ const cause = (error as any)?.cause;
228
+ // Return unwrapped cause (the actual Error object)
229
+ // error.cause should be an Error, but ensure it is
230
+ const unwrappedCause = cause instanceof Error ? cause : error;
231
+ throw new WorkflowError({
232
+ message: 'Failed to sendEmail',
233
+ errorCause: unwrappedCause,
234
+ });
235
+ }
236
+
237
+ // For all other errors
312
238
  throw new WorkflowError({
313
239
  message: 'Failed to sendEmail',
314
240
  errorCause: error,
@@ -11,20 +11,41 @@ export type Address = string;
11
11
 
12
12
  export type TimeStamp = string;
13
13
 
14
+ export type GrantedAccess = {
15
+ dataset: string;
16
+ datasetprice: string;
17
+ volume: string;
18
+ tag: string;
19
+ apprestrict: string;
20
+ workerpoolrestrict: string;
21
+ requesterrestrict: string;
22
+ salt: string;
23
+ sign: string;
24
+ remainingAccess: number;
25
+ };
26
+
14
27
  export type Contact = {
15
28
  address: Address;
16
29
  owner: Address;
17
30
  accessGrantTimestamp: TimeStamp;
18
31
  isUserStrict: boolean;
19
- name: string;
32
+ name?: string;
20
33
  remainingAccess: number;
21
34
  accessPrice: number;
35
+ grantedAccess: GrantedAccess;
22
36
  };
23
37
 
24
38
  export type SendEmailParams = {
25
39
  emailSubject: string;
26
40
  emailContent: string;
27
- protectedData: Address;
41
+ protectedData?: Address;
42
+ /**
43
+ * Granted access to process.
44
+ * use prepareBulkRequest of dataprotector to create a bulk request.
45
+ * if not provided, the single message will be processed.
46
+ */
47
+ grantedAccess?: GrantedAccess[];
48
+ maxProtectedDataPerTask?: number;
28
49
  contentType?: string;
29
50
  senderName?: string;
30
51
  label?: string;
@@ -40,6 +61,7 @@ export type FetchMyContactsParams = {
40
61
  * Get contacts for this specific user only
41
62
  */
42
63
  isUserStrict?: boolean;
64
+ bulkOnly?: boolean;
43
65
  };
44
66
 
45
67
  export type FetchUserContactsParams = {
@@ -49,7 +71,7 @@ export type FetchUserContactsParams = {
49
71
  userAddress: Address;
50
72
  } & FetchMyContactsParams;
51
73
 
52
- export type SendEmailResponse = {
74
+ export type SendEmailSingleResponse = {
53
75
  taskId: string;
54
76
  };
55
77