diff --git a/src/web3telegram/prepareTelegramCampaign.ts b/src/web3telegram/prepareTelegramCampaign.ts index 5c359df..7d58e90 100644 --- a/src/web3telegram/prepareTelegramCampaign.ts +++ b/src/web3telegram/prepareTelegramCampaign.ts @@ -39,7 +39,7 @@ export const prepareTelegramCampaign = async ({ label, appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE, workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE, - grantedAccess, + grantedAccesses, maxProtectedDataPerTask, }: IExecConsumer & DappAddressConsumer & @@ -122,7 +122,7 @@ export const prepareTelegramCampaign = async ({ args: vLabel, inputFiles: [], secrets, - bulkAccesses: grantedAccess, + bulkAccesses: grantedAccesses, maxProtectedDataPerTask: vMaxProtectedDataPerTask, }); return { campaignRequest }; diff --git a/src/web3telegram/sendTelegramCampaign.ts b/src/web3telegram/sendTelegramCampaign.ts index 03171ef..14dbae0 100644 --- a/src/web3telegram/sendTelegramCampaign.ts +++ b/src/web3telegram/sendTelegramCampaign.ts @@ -7,12 +7,12 @@ import { } from '../utils/validators.js'; import { DataProtectorConsumer } from './internalTypes.js'; import { - BulkRequest, ProcessBulkRequestParams, ProcessBulkRequestResponse, } from '@iexec/dataprotector'; import { ValidationError } from 'yup'; import { + CampaignRequest, SendTelegramCampaignParams, SendTelegramCampaignResponse, } from './types.js'; @@ -29,7 +29,7 @@ export const sendTelegramCampaign = async ({ const vCampaignRequest = campaignRequestSchema() .required() .label('campaignRequest') - .validateSync(campaignRequest) as BulkRequest; + .validateSync(campaignRequest) as CampaignRequest; const vWorkerpoolAddressOrEns = addressOrEnsSchema() .required() @@ -41,13 +41,15 @@ export const sendTelegramCampaign = async ({ vCampaignRequest.workerpool.toLowerCase() !== vWorkerpoolAddressOrEns.toLowerCase() ) { - throw new ValidationError('Workerpool mismatch'); + throw new ValidationError( + "workerpoolAddressOrEns doesn't match campaignRequest workerpool" + ); } // Process bulk request const processBulkRequestResponse: ProcessBulkRequestResponse = await dataProtector.processBulkRequest({ - bulkRequest: vCampaignRequest as BulkRequest, + bulkRequest: vCampaignRequest, workerpool: vWorkerpoolAddressOrEns, }); diff --git a/src/web3telegram/types.ts b/src/web3telegram/types.ts index 92ca61b..39adbfb 100644 --- a/src/web3telegram/types.ts +++ b/src/web3telegram/types.ts @@ -12,6 +12,22 @@ export type Address = string; export type TimeStamp = string; +/** + * request to send email in bulk + * + * use `prepareEmailCampaign()` to create a `CampaignRequest` + * + * then use `sendEmailCampaign()` to send the campaign + */ +export type CampaignRequest = BulkRequest; + +/** + * authorization signed by the data owner granting access to this contact + * + * `GrantedAccess` are obtained by fetching contacts (e.g. `fetchMyContacts()` or `fetchUserContacts()`) + * + * `GrantedAccess` can be consumed for email campaigns (e.g. `prepareEmailCampaign()` then `sendEmailCampaign()`) + */ export type GrantedAccess = { dataset: string; datasetprice: string; @@ -70,11 +86,11 @@ export type SendTelegramResponse = { export type PrepareTelegramCampaignParams = { /** - * Granted access to process in bulk. + * List of `GrantedAccess` to contacts to send telegrams to in bulk. + * * use `fetchMyContacts({ bulkOnly: true })` to get granted accesses. - * if not provided, the single message will be processed. */ - grantedAccess: GrantedAccess[]; + grantedAccesses: GrantedAccess[]; maxProtectedDataPerTask?: number; senderName?: string; telegramContent: string; @@ -86,11 +102,22 @@ export type PrepareTelegramCampaignParams = { }; export type PrepareTelegramCampaignResponse = { - campaignRequest: BulkRequest; + /** + * The prepared campaign request + * + * Use this in `sendTelegramCampaign()` to start or continue sending the campaign + */ + campaignRequest: CampaignRequest; }; export type SendTelegramCampaignParams = { - campaignRequest: BulkRequest; + /** + * The prepared campaign request from prepareTelegramCampaign + */ + campaignRequest: CampaignRequest; + /** + * Workerpool address or ENS to use for processing + */ workerpoolAddressOrEns?: string; }; diff --git a/tests/e2e/prepareTelegramCampaign.test.ts b/tests/e2e/prepareTelegramCampaign.test.ts index fbb076f..45f4fe4 100644 --- a/tests/e2e/prepareTelegramCampaign.test.ts +++ b/tests/e2e/prepareTelegramCampaign.test.ts @@ -101,7 +101,7 @@ describe('web3telegram.prepareTelegramCampaign()', () => { telegramContent: 'Bulk test message', senderName: 'Bulk test sender', // protectedData is optional when grantedAccess is provided - grantedAccess: bulkOrders, + grantedAccesses: bulkOrders, maxProtectedDataPerTask: 3, workerpoolMaxPrice: prodWorkerpoolPublicPrice, }); diff --git a/tests/e2e/sendTelegramCampaign.test.ts b/tests/e2e/sendTelegramCampaign.test.ts index 08aeadc..c662250 100644 --- a/tests/e2e/sendTelegramCampaign.test.ts +++ b/tests/e2e/sendTelegramCampaign.test.ts @@ -141,44 +141,16 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { const bulkOrders = contacts.map((contact) => contact.grantedAccess); - // Prepare the telegram campaign using prepareTelegramCampaign - // Note: This may fail on networks that don't support bulk processing (e.g., bellecour) - // We expect this error and handle it gracefully - let bulkProcessingAvailable = true; - let campaignRequest; - try { - const prepareResult = await web3telegram.prepareTelegramCampaign({ - telegramContent: 'Bulk test message', - grantedAccess: bulkOrders, - maxProtectedDataPerTask: 3, - appMaxPrice: 1000, - workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, - senderName: 'Bulk Test Sender', - }); - campaignRequest = prepareResult.campaignRequest; - } catch (error: unknown) { - // Expect error if bulk processing is not available on this network - // The error message is "Failed to prepareTelegramCampaign" but the cause contains the actual reason - const errorMessage = error instanceof Error ? error.message : ''; - const errorCause = - error instanceof Error && error.cause - ? error.cause instanceof Error - ? error.cause.message - : String(error.cause) - : ''; - const fullError = `${errorMessage} ${errorCause}`; - if (fullError.includes('Bulk processing is not available')) { - bulkProcessingAvailable = false; - } else { - throw error; - } - } - - // Skip the rest of the test if bulk processing is not supported - if (!bulkProcessingAvailable) { - return; - } + const prepareResult = await web3telegram.prepareTelegramCampaign({ + telegramContent: 'Bulk test message', + grantedAccesses: bulkOrders, + maxProtectedDataPerTask: 3, + appMaxPrice: 1000, + workerpoolMaxPrice: 1000, + workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + senderName: 'Bulk Test Sender', + }); + const campaignRequest = prepareResult.campaignRequest; // Process the bulk request using sendTelegramCampaign // Use the workerpool from campaignRequest (already resolved to address) @@ -218,39 +190,16 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Use only the first contact const bulkOrders = [contacts[0].grantedAccess]; - // Prepare the telegram campaign using prepareTelegramCampaign - let bulkProcessingAvailable = true; - let campaignRequest; - try { - const prepareResult = await web3telegram.prepareTelegramCampaign({ - telegramContent: 'Single contact bulk test message', - grantedAccess: bulkOrders, - maxProtectedDataPerTask: 1, - appMaxPrice: 1000, - workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, - senderName: 'Single Contact Test', - }); - campaignRequest = prepareResult.campaignRequest; - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : ''; - const errorCause = - error instanceof Error && error.cause - ? error.cause instanceof Error - ? error.cause.message - : String(error.cause) - : ''; - const fullError = `${errorMessage} ${errorCause}`; - if (fullError.includes('Bulk processing is not available')) { - bulkProcessingAvailable = false; - } else { - throw error; - } - } - - if (!bulkProcessingAvailable) { - return; - } + const prepareResult = await web3telegram.prepareTelegramCampaign({ + telegramContent: 'Single contact bulk test message', + grantedAccesses: bulkOrders, + maxProtectedDataPerTask: 1, + appMaxPrice: 1000, + workerpoolMaxPrice: 1000, + workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + senderName: 'Single Contact Test', + }); + const campaignRequest = prepareResult.campaignRequest; // Process the bulk request using sendTelegramCampaign // Use the workerpool from campaignRequest (already resolved to address) @@ -287,41 +236,17 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { const bulkOrders = contacts.map((contact) => contact.grantedAccess); - // Prepare the telegram campaign with maxProtectedDataPerTask = 1 - // This should create multiple tasks if we have more than 1 contact - let bulkProcessingAvailable = true; - let campaignRequest; - try { - const prepareResult = await web3telegram.prepareTelegramCampaign({ - telegramContent: 'Max protected data per task test', - grantedAccess: bulkOrders, - maxProtectedDataPerTask: 1, // Force one protected data per task - appMaxPrice: 1000, - workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, - senderName: 'Max Data Test', - label: 'MAXDATA', - }); - campaignRequest = prepareResult.campaignRequest; - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : ''; - const errorCause = - error instanceof Error && error.cause - ? error.cause instanceof Error - ? error.cause.message - : String(error.cause) - : ''; - const fullError = `${errorMessage} ${errorCause}`; - if (fullError.includes('Bulk processing is not available')) { - bulkProcessingAvailable = false; - } else { - throw error; - } - } - - if (!bulkProcessingAvailable) { - return; - } + const prepareResult = await web3telegram.prepareTelegramCampaign({ + telegramContent: 'Max protected data per task test', + grantedAccesses: bulkOrders, + maxProtectedDataPerTask: 1, // Force one protected data per task + appMaxPrice: 1000, + workerpoolMaxPrice: 1000, + workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + senderName: 'Max Data Test', + label: 'MAXDATA', + }); + const campaignRequest = prepareResult.campaignRequest; // Process the bulk request using sendTelegramCampaign // Use the workerpool from campaignRequest (already resolved to address) @@ -356,40 +281,17 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { const bulkOrders = contacts.map((contact) => contact.grantedAccess); - // Prepare the telegram campaign with custom parameters - let bulkProcessingAvailable = true; - let campaignRequest; - try { - const prepareResult = await web3telegram.prepareTelegramCampaign({ - telegramContent: 'Custom parameters test message', - grantedAccess: bulkOrders, - maxProtectedDataPerTask: 3, - appMaxPrice: 1000, - workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, - senderName: 'CustomSender', - label: 'CUSTOM123', - }); - campaignRequest = prepareResult.campaignRequest; - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : ''; - const errorCause = - error instanceof Error && error.cause - ? error.cause instanceof Error - ? error.cause.message - : String(error.cause) - : ''; - const fullError = `${errorMessage} ${errorCause}`; - if (fullError.includes('Bulk processing is not available')) { - bulkProcessingAvailable = false; - } else { - throw error; - } - } - - if (!bulkProcessingAvailable) { - return; - } + const prepareResult = await web3telegram.prepareTelegramCampaign({ + telegramContent: 'Custom parameters test message', + grantedAccesses: bulkOrders, + maxProtectedDataPerTask: 3, + appMaxPrice: 1000, + workerpoolMaxPrice: 1000, + workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + senderName: 'CustomSender', + label: 'CUSTOM123', + }); + const campaignRequest = prepareResult.campaignRequest; // Process the bulk request using sendTelegramCampaign // Use the workerpool from campaignRequest (already resolved to address) @@ -417,39 +319,16 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { const bulkOrders = contacts.map((contact) => contact.grantedAccess); - // Prepare the telegram campaign - let bulkProcessingAvailable = true; - let campaignRequest; - try { - const prepareResult = await web3telegram.prepareTelegramCampaign({ - telegramContent: 'Workerpool mismatch test', - grantedAccess: bulkOrders, - maxProtectedDataPerTask: 3, - appMaxPrice: 1000, - workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, - senderName: 'Mismatch Test', - }); - campaignRequest = prepareResult.campaignRequest; - } catch (error: unknown) { - const errorMessage = error instanceof Error ? error.message : ''; - const errorCause = - error instanceof Error && error.cause - ? error.cause instanceof Error - ? error.cause.message - : String(error.cause) - : ''; - const fullError = `${errorMessage} ${errorCause}`; - if (fullError.includes('Bulk processing is not available')) { - bulkProcessingAvailable = false; - } else { - throw error; - } - } - - if (!bulkProcessingAvailable) { - return; - } + const prepareResult = await web3telegram.prepareTelegramCampaign({ + telegramContent: 'Workerpool mismatch test', + grantedAccesses: bulkOrders, + maxProtectedDataPerTask: 3, + appMaxPrice: 1000, + workerpoolMaxPrice: 1000, + workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + senderName: 'Mismatch Test', + }); + const campaignRequest = prepareResult.campaignRequest; // Try to send with a different workerpool (should fail) const differentWorkerpool = @@ -463,7 +342,8 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { message: 'Failed to sendTelegramCampaign', cause: expect.objectContaining({ name: 'ValidationError', - message: 'Workerpool mismatch', + message: + "workerpoolAddressOrEns doesn't match campaignRequest workerpool", }), }); }, diff --git a/tests/unit/sendTelegramCampaign.test.ts b/tests/unit/sendTelegramCampaign.test.ts index b943a6e..8362b5e 100644 --- a/tests/unit/sendTelegramCampaign.test.ts +++ b/tests/unit/sendTelegramCampaign.test.ts @@ -504,7 +504,8 @@ describe('sendTelegramCampaign', () => { message: 'Failed to sendTelegramCampaign', cause: expect.objectContaining({ name: 'ValidationError', - message: 'Workerpool mismatch', + message: + "workerpoolAddressOrEns doesn't match campaignRequest workerpool", }), });